Spring-day01 IoC

  1. # 框架阶段
  2. 1. 时间 (8天)
  3. 1). spring : 3
  4. 2). springmvc : 2
  5. 3). maven高级 : 1
  6. 5). springboot 1
  7. 6). 综合案例: 1
  8. 2. SSM
  9. 1). springmvc (web层)
  10. 2). spring (service,dao层)
  11. 3). mybatis (dao层)

1)Spring简介

1.1)什么是框架 (framework)

  • 源自于建筑学,隶属土木工程,后发展到软件工程领域

  • 软件工程框架:经过验证的,具有一定功能的,半成品软件

    • 经过验证

    • 具有一定功能

    • 半成品

Spring-day01-课堂笔记 - 图1

1.2)框架的作用

Spring-day01-课堂笔记 - 图2

1.3)Spring是什么

官网:https://spring.io/

Spring-day01-课堂笔记 - 图3

  1. Spring是一个开源框架,Spring的核心是控制反转(IoC)和面向切面(AOP)。简单来说,Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。

轻量级:与EJB对比,依赖资源少,消耗的资源少。
分层: 一站式,每一个层都提供的解决方案

  • web层:struts2,Spring-MVC
  • service层:spring
  • dao层:hibernate,mybatis , jdbcTemplate —> spring-data

1.4)Spring的发展历史

java :

  1. SE: standard edition 标准
  2. ME: micro edition 微型
  3. EE: enterprice edition 企业

Spring-day01-课堂笔记 - 图4

Spring的发展历史:
1997年IBM提出了EJB的思想(EJB是的Enterprise Java Beans技术的简称, 又被称为企业Java Beans)
1998年,SUN制定开发标准规范EJB1.0
1999年,EJB1.1发布
2001年,EJB2.0发布
2003年,EJB2.1发布
2006年,EJB3.0发布

Rod Johnson(spring之父)
Expert One-to-One J2EE Design and Development(2002)
阐述了J2EE使用EJB开发设计的优点及解决方案

  1. Expert One-to-One J2EE Development without EJB(2004)<br />
  2. 阐述了J2EE开发不使用EJB的解决方式(Spring雏形)

2017年9月份发布了spring的最新版本—spring 5.0通用版

  1. 备注:EJB说白了就是把编写的软件中那些需要执行制定的任务的类,不放到客户端软件上了,而是给他打成包放到一个服务器上;

1.5)Spring的体系结构

Spring-day01-课堂笔记 - 图5

1.6)Spring优势

Spring 出现是为了解决JavaEE 实际问题:

  • 方便解耦,简化开发 (IOC)
    Spring就是一个大工厂(容器),可以将所有对象创建和依赖关系维护,交给Spring管理
    Spring工厂是用于生成bean

  • AOP编程的支持
    Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能

  • 声明式事务的支持
    只需要通过配置就可以完成对事务的管理,而无需手动编程

  • 方便程序的测试
    Spring对Junit4支持,可以通过注解方便的测试Spring程序

  • 方便集成各种优秀框架
    Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持

  • 降低JavaEE API的使用难度
    Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低

基于这些特性,我们也会俗称Spring为开发架构的粘合剂

1.7)Spring核心

Spring为企业级开发提供了丰富的功能,这些功能的底层都依赖于它的两个核心特性:

  • 控制反转(Inversion of Control,IOC
  • 面向切面编程(aspect-oriented programming,AOP

Spring类似于航母,可以集成其他的框架

2)IoC简介

2.1)优质程序代码的制作原则

  • 耦合(Coupling):代码书写过程中所使用技术的结合紧密度,用于衡量软件中各个模块之间的互联程度

    • 耦合可以发生在方法与方法之间,类与类之间、模块与模块之间等;
    • eg:A方法的实现调用并依赖了B方法,我们就说A与B方法存在耦合;
  • 内聚(Cohesion):代码书写过程中单个模块内部各组成部分间的联系,用于衡量软件中各个功能模块内部的功能联系

Spring-day01-课堂笔记 - 图6

  • 程序书写的目标:高内聚,低耦合

    • 就是同一个模块内的各个元素之间要高度紧密,但是各个模块之间的相互依存度却不要那么紧密
    • 好处: 便于代码的长期维护和扩展
  1. # 场景: 人打开门
  2. 1.
  3. 2. : 打开
  4. 内聚 : 打开这个行为,脱离了'门'没有意义, 所以'打开'设计给'门'
  5. 耦合 : 如果把'打开'设计给'人' , 那么'猫' '狗'也可能需要添加'打开',代码冗余,而且脱离不了门, 耦合

2.2)工厂模式的代码演变

Spring-day01-课堂笔记 - 图7

  1. package com.itheima.ioc.dao;
  2. public interface UserDao {
  3. void addUser();
  4. void deleteUser();
  5. void updateUser();
  6. void queryUser();
  7. }
  1. package com.itheima.ioc.dao.impl;
  2. import com.itheima.ioc.dao.UserDao;
  3. public class UserDaoImpl implements UserDao {
  4. @Override
  5. public void addUser() {
  6. System.out.println("添加用户");
  7. }
  8. @Override
  9. public void deleteUser() {
  10. System.out.println("删除用户");
  11. }
  12. @Override
  13. public void updateUser() {
  14. System.out.println("修改用户");
  15. }
  16. @Override
  17. public void queryUser() {
  18. System.out.println("查询用户");
  19. }
  20. }
  1. package com.itheima.ioc.service;
  2. public interface UserService {
  3. void add() throws Exception;
  4. }
  1. package com.itheima.ioc.service.impl;
  2. import com.itheima.ioc.dao.UserDao;
  3. import com.itheima.ioc.dao.impl.UserDaoImpl;
  4. import com.itheima.ioc.dao.impl.UserDaoImpl2;
  5. import com.itheima.ioc.service.UserService;
  6. import com.itheima.ioc.util.BeanFactory;
  7. import com.itheima.ioc.util.UnfinishedBeanFactory;
  8. import org.junit.Test;
  9. import java.util.ResourceBundle;
  10. public class UserServiceImpl implements UserService {
  11. @Test
  12. @Override
  13. public void add() throws Exception {
  14. //1. 主动创建对象
  15. //存在的问题:1.代码耦合:UserServiceImpl#add()实现依赖于UserDaoImpl,我们就说
  16. //UserServiceImpl与UserDaoImpl存在耦合
  17. //问题2:如果UserDao接口的方法做了另外一套实现,那么也需要改动代码
  18. // UserDaoImpl userDao = new UserDaoImpl();
  19. // UserDaoImpl2 userDao2=new UserDaoImpl2();
  20. // 2. 面向接口编程 : 解耦(一定程度的解耦)
  21. //思考:UserDao userDao = new UserDaoImpl()只有当前方法使用么?
  22. //答案:显然不是,会构建很多构建userDao的方法
  23. //核心思路:把共性代码提取到一个工具类中,而这段代码仅仅只有生成对象,所以这个工具类可
  24. //称为工厂类
  25. // UserDao userDao = new UserDaoImpl();
  26. // UserDao userDao = new UserDaoImpl2();
  27. //3.构建userDao对象的方法封装到统一工厂中:解耦服务对象与dao对象
  28. // UserDao userDao= (UserDao) UnfinishedBeanFactory.getBean("userDao");
  29. // 4. 反射 + 配置文件 : 进一步解耦
  30. // ResourceBundle bundle = ResourceBundle.getBundle("data");
  31. // String userDaoClassName = bundle.getString("userDao");
  32. // Class<?> clazz = Class.forName(userDaoClassName);
  33. // UserDao userDao = (UserDao) clazz.newInstance();
  34. //5. 工厂模式 : 统一管理bean的创建
  35. //工厂类+反射+配置文件实现最大程度的解耦
  36. //思路:
  37. //1.工厂类不要反复构建对象,尽量让构建好的对象增强复用性,好处:节约内存,且响应速度提升
  38. //如何提高工厂生产的对象的复用性?对象池----》IOC容器
  39. //2.将工厂生产的对象通过静态资源配置后,好处:1.解耦了工厂与资源的耦合 2.避免因资源的调整而反复编译工厂的问题,提高了可维护性
  40. UserDao userDao = (UserDao) BeanFactory.getBean("userDao");
  41. userDao.addUser();
  42. }
  43. }
  1. package com.itheima.ioc.util;
  2. import java.util.Enumeration;
  3. import java.util.HashMap;
  4. import java.util.Map;
  5. import java.util.ResourceBundle;
  6. public class BeanFactory {
  7. //1、事先存储容器
  8. private static Map<String, Object> map = new HashMap<>();
  9. //2、加载配置文件
  10. static {
  11. /*
  12. 好处:经动态资源静态配置化,避免了因为资源的调整而带来的反复编译的维护成本
  13. 弊端:静态配置文件与资源也会存在耦合,但是耦合已经降到最低了
  14. 结论:高内聚 低耦合,而不说高内聚 零耦合?
  15. 耦合不能彻底消除,只能降低!
  16. */
  17. ResourceBundle bundle = ResourceBundle.getBundle("data");
  18. try {
  19. Enumeration<?> enumeration = bundle.getKeys();
  20. while (enumeration.hasMoreElements()) {
  21. String key = (String) enumeration.nextElement();
  22. String value = (String) bundle.getString(key);
  23. //3、实例化bean
  24. Object beanObject = Class.forName(value).newInstance();
  25. //4、放入容器
  26. map.put(key,beanObject);
  27. }
  28. } catch (Exception e) {
  29. e.printStackTrace();
  30. }
  31. }
  32. //5、公共获得bean
  33. public static Object getBean(String calssName){
  34. return map.get(calssName);
  35. }
  36. }

2.3)Spring发展历程

Spring-day01-课堂笔记 - 图8

2.4)IoC

  1. # IOC概念
  2. 0. IoC 全称为 Inversion of Control,翻译为 “控制反转”。
  3. 1. 控制什么?
  4. 控制对象的创建和销毁
  5. 2. 反转什么?
  6. 对象的控制权(创建和销毁)从主动管理转为交给Spring的容器管理
  7. 3. Spring的容器(IOC Container)
  8. Spring控制的资源全部放置在Spring容器中,该容器也称为IoC容器
  9. 4. IOC的思想
  10. 1). 面向接口编程 (多态)
  11. 接口类型 变量 = 接口实现类对象
  12. 2). 反射 + 配置文件
  13. 3). 工厂模式: 内置容器,管理对象的创建和销毁
  14. 5. IOC的作用: 解耦

Spring-day01-课堂笔记 - 图9

3)入门案例

spring文档

https://docs.spring.io/spring-framework/docs/5.1.19.RELEASE/spring-framework-reference/core.html#spring-core

3.1)案例环境说明

  • 模拟三层架构中表现层调用业务层功能

    • 表现层:UserTest模拟UserServlet(使用@Test方法模拟)

    • 业务层:UserService (spring 在业务层解耦IOC和增强AOP)

3.2)IoC入门案例制作步骤

1.导入spring坐标(5.1.9.release)

2.编写业务层与表现层(模拟)接口与实现类

3.建立spring配置文件

4.配置所需资源(Service)为spring控制的资源

5.表现层(UserTest)通过spring获取资源(Service实例)

代码结构如下

Spring-day01-课堂笔记 - 图10

3.2.1)IoC入门案例制作步骤-1

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework</groupId>
  4. <artifactId>spring-context</artifactId>
  5. <version>5.1.9.RELEASE</version>
  6. </dependency>
  7. </dependencies>

3.2.2)IoC入门案例制作步骤-2

  1. public interface UserService {
  2. //业务方法
  3. void save();
  4. }

3.2.3)IoC入门案例制作步骤-3

  1. public class UserServiceImpl implements UserService {
  2. public void save() {
  3. System.out.println("user service running...");
  4. }
  5. }

3.2.4)IoC入门案例制作步骤-4

配置文件

applicationContext.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. https://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <!-- 1.创建spring控制的资源
  7. 1). id 是这个bean的标识, 可以自定义,但是最好见名知意
  8. 2). class 指定实现类的全限定名
  9. -->
  10. <bean id="userService" class="com.itheima.service.impl.UserServiceImpl"/>
  11. </beans>

3.2.5)IoC入门案例制作步骤-5

测试类

  1. public class UserTest {
  2. @Test
  3. public void test01(){
  4. //2.加载配置文件
  5. ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
  6. //3.获取资源: 通过配置文件中的id
  7. UserService userService = (UserService) ctx.getBean("userService");
  8. userService.save();
  9. }
  10. }

3.3) 入门案例原理

3.31)ApplicationContext

1.ApplicationContext是一个接口,提供了访问spring容器的API

2.ClassPathXmlApplicationContext是一个类,实现了上述功能

3.ApplicationContext的顶层接口是BeanFactory

4.BeanFactory定义了bean相关的最基本操作

5.ApplicationContext在BeanFactory基础上追加了若干新功能

Spring-day01-课堂笔记 - 图11

3.32 原理描述

  1. package com.itheima.test;
  2. import com.itheima.service.UserService;
  3. import org.junit.Test;
  4. import org.springframework.context.ApplicationContext;
  5. import org.springframework.context.annotation.AnnotationConfigApplicationContext;
  6. import org.springframework.context.support.ClassPathXmlApplicationContext;
  7. /*
  8. * # IOC重要角色
  9. * 1. 工厂
  10. * 1). BeanFactory 父接口
  11. * 2). ApplicationContext 子接口
  12. * 3). ClassPathXmlApplicationContext 实现类 (加载类路径下xml配置文件的工厂)
  13. * 4). AnnotationConfigApplicationContext 实现类 (加载注解配置的工厂)
  14. * 特点:
  15. * I. 会加载配置文件
  16. * a. properties文件 -> 解析 Properties(Map)/ ResourceBundle
  17. * b. xml文件 -> 解析 sax/dom (dom4j)
  18. * c. 注解 -> 解析 反射
  19. * 语法不同, 解析方案不同
  20. * II. 访问容器的入口
  21. * Map<String,Object>
  22. *
  23. * 2. 配置
  24. * 1). xml配置
  25. * 2). 注解
  26. *
  27. * 3. bean
  28. * 在xml/注解中配置
  29. * 从容器中获取
  30. *
  31. * # 记录
  32. * 1. 快捷键
  33. * 1). ctrl + alt + u : 选中一个类, 查看这个类继承体系
  34. *
  35. * */
  36. public class UserTest {
  37. @Test
  38. public void test01(){
  39. //2.加载配置文件
  40. ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
  41. // ApplicationContext ctx = new AnnotationConfigApplicationContext();
  42. //3.获取资源: 通过配置文件中的id
  43. UserService userService = (UserService) ctx.getBean("userService");
  44. userService.save();
  45. }
  46. }

4)IoC配置(XML格式)

4.1)bean

  • 名称:bean

  • 类型:标签

  • 归属:beans标签

  • 作用:定义spring中的资源,受此标签定义的资源将受到spring控制

  • 格式:

    1. <beans>
    2. <bean />
    3. </beans>
  • 基本属性:
    1. <bean id="beanId" name="beanName1,beanName2" class="ClassName"></bean>


id:bean的名称,通过id值获取bean
class:bean的类型 (全限定名)
name:bean的名称,可以通过name值获取bean,用于多人配合时给bean起别名

  • 代码演示

    1. 配置文件修改
      1. <!-- name和id的作用相似, 我们也可以通过name获取bean -->
      2. <bean id="userService" name="userService1,userService2" class="com.itheima.service.impl.UserServiceImpl"/>
  1. 测试类修改

    1. public class UserTest {
    2. @Test
    3. public void test01(){
    4. //2.加载配置文件
    5. ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    6. //3.获取资源: 通过id和name都能获取到bean
    7. // userService,userService1,userService2都可以
    8. // userService3 因为没有指定,所以会报以下异常:
    9. // NoSuchBeanDefinitionException: No bean named 'userService3' available
    10. UserService userService = (UserService) ctx.getBean("userService3");
    11. userService.save();
    12. }
    13. }

4.2)bean属性scope

  • 名称:scope

  • 类型:属性

  • 归属:bean标签

  • 作用:定义bean的作用范围

  • 格式:

    1. <bean scope="singleton"></bean>
  • 取值:

    • singleton:设定创建出的对象保存在spring容器中,是一个单例的对象,默认的属性
    • prototype:spring容器只负责构建对象,内部不保存维护,是一个非单例的对象
    • request、session、application、 websocket :设定创建出的对象放置在web容器对应的位置 (了解)
  • 代码演示

    1. 配置文件修改

      1. <!--
      2. scope : 作用范围
      3. 1. singleton : 单例 (默认值)
      4. 1). 这个类在容器只会有一个实例
      5. 2). 饿汉单例 : 工厂加载配置文件的时候,实例就创建了
      6. 效率高
      7. 2. prototype : 多例
      8. 1). 这个类在容器有多个实例
      9. 2). 懒汉多例 : 工厂加载配置文件的时候,没有实例, 获取的时候才创建
      10. 3. 运用:
      11. 1). 单例: 全工程只要一个实例 (连接池,线程池,工厂...)
      12. 2). 多例: 全工程需要多个实例 (连接,线程 ... )
      13. -->
      14. <bean id="userService" class="com.itheima.service.impl.UserServiceImpl"
      15. scope="prototype"
      16. />
  1. 测试类修改
    1. public class UserServiceImpl implements UserService {
    2. public UserServiceImpl(){
    3. System.out.println("constructor run...");
    4. }
    5. @Override
    6. public void save() {
    7. System.out.println("UserServiceImpl run...");
    8. }
    9. }
  1. @Test
  2. public void test02(){
  3. ApplicationContext ctx
  4. = new ClassPathXmlApplicationContext("applicationContext.xml");
  5. UserService userService1 = (UserService) ctx.getBean("userService");
  6. UserService userService2 = (UserService) ctx.getBean("userService");
  7. // System.out.println(userService1);
  8. // System.out.println(userService2);
  9. }

4.3)bean生命周期

Spring中bean对象的创建到销毁的整个过程就是bean的生命周期;

  • 名称:init-method,destroy-method

  • 类型:属性

  • 归属:bean标签

  • 作用:定义bean对象在初始化或销毁时完成的工作

  • 格式:

    1. <bean init-method="init" destroy-method="destroy"></bean>
  • 取值:bean对应的类中对应的具体方法名

  • 注意事项:

    • 当scope=“singleton”时,spring容器中有且仅有一个对象,init方法在创建容器时仅执行一次

    • 当scope=“prototype”时,spring容器要创建同一类型的多个对象,init方法在每个对象创建时均执行一次

    • 当scope=“singleton”时,关闭容器会导致bean实例的销毁,调用destroy方法一次

    • 当scope=“prototype”时,对象的销毁由垃圾回收机制gc()控制,destroy方法将不会被执行

  • 代码演示

    1. 实现类修改

      1. public class UserServiceImpl implements UserService {
      2. public UserServiceImpl(){
      3. System.out.println("UserServiceImpl constructor..");
      4. }
      5. @Override
      6. public void save() {
      7. System.out.println("userService save--");
      8. }
      9. public void a(){
      10. System.out.println("init");
      11. }
      12. public void destroy(){
      13. System.out.println("destroy");
      14. }
      15. }
  1. 配置文件

    1. <!--
    2. bean的生命周期方法
    3. 0. 概念
    4. 生命周期: 从创建到销毁的整个过程
    5. bean的生命周期方法 : 在一个bean从创建到销毁的整个过程中执行的方法
    6. 1. init-method : 用来指定bean的init方法(初始化)
    7. 执行时机: 此方法bean创建的时候调用
    8. 适合 : 初始化数据
    9. 2. destroy-method : 用来指定bean的destroy方法(销毁)
    10. 此方法bean销毁的时候调用
    11. 适合 : 保存数据,释放资源
    12. 底层原理:
    13. Class clazz = Class.forName("com.itheima.service.impl.UserServiceImpl");
    14. Object obj = clazz.newInstance(); // 通过空参构造创建实例
    15. //在类中,找到名为a的public空参方法
    16. Method method = clazz.getMethod("a");
    17. //调用方法
    18. method.invoke(obj);
    19. 饿汉单例:
    20. 1. 初始化: 工厂创建,bean就会被加载, bean的init方法就会执行
    21. 2. 销毁 : 程序终止, 工厂(ioc容器)销毁,bean也会随之销毁,destroy方法就会执行
    22. 懒汉多例 :
    23. 1. 初始化 : 每从ioc容器中获取一个bean,就会创建一个bean,init方法就会被调用一次
    24. 2. 销毁 : bean对象不由ioc容器管理, ioc容器销毁, bean不会随之销毁的,destroy不执行
    25. 由GC管理(垃圾回收器)
    26. -->
    27. <bean id="userService"
    28. scope="prototype"
    29. class="com.itheima.service.impl.UserServiceImpl"
    30. init-method="a"
    31. destroy-method="destroy"
    32. />
  1. 测试类修改
    1. @Test
    2. public void method03(){
    3. //1. 创建工厂对象
    4. ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    5. //2. 从ioc容器中获取bean
    6. UserService userService = (UserService) context.getBean("userService");
    7. UserService userService2 = (UserService) context.getBean("userService");
    8. /*
    9. 工厂销毁(当程序运行结束时, 工厂就会销毁)
    10. 1. 如果程序正常运行终止, 工厂是会销毁的,但是因为demo的运行太快, destroy有执行
    11. 但是时间太短, 看不到destroy,所以现在手动调用close方法(这个代码没必要写)
    12. 2. close方法是属于 ClassPathXmlApplicationContext特有的,ApplicationContext没有
    13. */
    14. ClassPathXmlApplicationContext ctx = (ClassPathXmlApplicationContext) context;
    15. ctx.close();
    16. }

4.4)bean对象创建方式

  1. # bean对象的创建方式
  2. 1. 直接配置
  3. <bean id="userService" class="com.itheima.service.impl.UserServiceImpl"/>
  4. 场景: 在配置的时候,知道实现类的全限定名 (一般自己写bean)
  5. 底层原理: 空参构造(有参构造涉及到DI依赖注入,后边会讲)
  6. 缺陷是: 开发者需要知道类名
  7. 2. 工厂方式
  8. 1). 静态工厂 : 创建对象的方法是静态
  9. 2). 实例工厂 : 创建对象的方法是非静态的
  10. 场景: 开发者不知道类名,但是可以通过代码创建实例
  11. I. 匿名内部类
  12. II. 动态代理 : 代理类是运行时动态创建的,开发者不知道类名

除了以上所示的通过调用bean的构造方法创建对象之外,spring还提供了两种工厂创建方式

一般用来配置其他框架的bean

(1)静态工厂

  • 名称:factory-bean

  • 类型:属性

  • 归属:bean标签

  • 作用:定义bean对象创建方式,使用静态工厂的形式创建bean,兼容早期遗留系统的升级工作

  • 格式:

    1. <bean class="FactoryClassName" factory-method="factoryMethodName"></bean>
  • 取值:工厂bean中用于获取对象的静态方法名

  • 注意事项:
    class属性必须配置成静态工厂的类名

  • 测试代码:

    1. 新增一个静态工厂类 ```java package com.itheima.service.impl;

import com.itheima.service.UserService;

public class UserServiceImpl2 implements UserService {

  1. int a;
  2. public UserServiceImpl2(int a){
  3. this.a = a;
  4. }
  5. public void save() {
  6. System.out.println("user service2 running...");
  7. }

}

  1. ```java
  2. package com.itheima.factory;
  3. import com.itheima.service.UserService;
  4. import com.itheima.service.impl.UserServiceImpl2;
  5. /*
  6. 静态工厂: 方法是静态的
  7. */
  8. public class StaticFactory {
  9. public static UserService getBean(){
  10. UserServiceImpl2 service = new UserServiceImpl2(1);
  11. return service;
  12. }
  13. }
  1. 配置文件修改

    1. <!--
    2. 如果一个类没有空参构造,就不能用 bean:id,class方法配置
    3. 1. 静态工厂
    4. 2. 实例工厂
    5. # 静态工厂的原理
    6. clazz = Class.forName("com.itheima.factory.StaticFactory");
    7. getBean = clazz.getMethod("getBean");
    8. UserService service = getBean.invoke(null);
    9. map.put("userService2",service);
    10. -->
    11. <bean id="userService2" class="com.itheima.factory.StaticFactory"
    12. factory-method="getBean"/>
  1. 测试类修改

    1. @Test
    2. public void test04(){
    3. ApplicationContext ctx
    4. = new ClassPathXmlApplicationContext("applicationContext.xml");
    5. UserService service = (UserService) ctx.getBean("userService2");
    6. service.save();
    7. }


打印结果:

user service2 running…

(2)实例工厂

  • 名称:factory-bean,factory-method

  • 类型:属性

  • 归属:bean标签

  • 作用:定义bean对象创建方式,使用实例工厂的形式创建bean,兼容早期遗留系统的升级工作

  • 格式:

    1. <bean factory-bean="factoryBeanId" factory-method="factoryMethodName"></bean>
  • 取值:工厂bean中用于获取对象的实例方法名

  • 注意事项:

    • 使用实例工厂创建bean首先需要将实例工厂配置bean,交由spring进行管理
    • factory-bean是实例工厂的beanId
  • 测试代码

    1. 创建实例工厂 ```java package com.itheima.factory;

import com.itheima.service.UserService; import com.itheima.service.impl.UserServiceImpl2; /*

  • 实例工厂: 方法是非静态
  • */ public class InstanceFactory {

    public UserService getBean(){

    1. UserServiceImpl2 service = new UserServiceImpl2(1);
    2. return service;

    } } ```

  1. 配置文件修改
  1. <!--
  2. # 实例工厂的原理
  3. clazz = Class.forName("com.itheima.factory.InstanceFactory");
  4. if = clazz.newInstance();
  5. getBean = clazz.getMethod("getBean")
  6. UserService service = getBean.invoke(if);
  7. map.put("userService3",service);
  8. -->
  9. <bean id="if" class="com.itheima.factory.InstanceFactory"/>
  10. <bean id="userService3" factory-bean="if" factory-method="getBean"/>
  1. 测试类修改

    1. @Test
    2. public void test04(){
    3. ApplicationContext ctx
    4. = new ClassPathXmlApplicationContext("applicationContext.xml");
    5. UserService service = (UserService) ctx.getBean("userService3");
    6. service.save();
    7. }


运行结果

user service2 running…

4.5)DI 依赖注入

  • IoC(Inversion Of Control)控制翻转,Spring反向控制应用程序所需要使用的外部资源

  • DI(Dependency Injection)依赖注入,应用程序运行依赖的资源由Spring为其提供,资源进入应用程序的方式称为注入

Spring-day01-课堂笔记 - 图12

举例:

  1. UserService <-------> UserDao
  • 站在对象构建的角度看:UserService的角度看,需要UserDao资源,而UserDao的构建需要通过springIOC容器反向构建—-》IOC
  • 站在资源使用的角度看:UserService需要的资源,需要被动等待SpringIOC容器给提供(等待容器给资源的需求方法注入资源,才可以用)—-》DI(大白话说,就是为bean对象注入属性资源);

示例:张三(男)和李四(女)结婚

  • 张三的亲友: 张三娶了李四
  • 李四的亲友: 李四嫁给了张三

IoC与DI是同一件事站在不同角度看待问题;

4.6)set注入(主流)

  • 名称:property

  • 类型:标签

  • 归属:bean标签

  • 作用:使用set方法的形式为bean提供资源

  • 格式:

    1. <bean>
    2. <property />
    3. </bean>
  • 基本属性:
    1. <property name="propertyName" value="propertyValue" ref="beanId"/>


name:对应bean中的属性名,要求该属性必须提供可访问的set方法(严格规范为此名称是set方法对应名称)
value:设定非引用类型(8大基本类型和String)属性对应的值,不能与ref同时使用
ref:设定引用类型属性对应bean的id ,不能与value同时使用(refrence)

  • 注意:一个bean可以有多个property标签

  • 代码演示

    1. 添加和修改代码 ```java package com.itheima.service.impl;

import com.itheima.dao.UserDao; import com.itheima.service.UserService;

import java.util.Date;

public class UserServiceImpl3 implements UserService {

  1. private String name;
  2. private int age;
  3. private UserDao dao;
  4. private Date date;
  5. public void save() {
  6. System.out.println(name + "," + age + "," + date);
  7. dao.add();
  8. }
  9. public Date getDate() {
  10. return date;
  11. }
  12. public void setDate(Date date) {
  13. this.date = date;
  14. }
  15. public String getName() {
  16. return name;
  17. }
  18. public void setName(String name) {
  19. this.name = name;
  20. }
  21. public int getAge() {
  22. return age;
  23. }
  24. public void setAge(int age) {
  25. this.age = age;
  26. }
  27. public UserDao getDao() {
  28. return dao;
  29. }
  30. public void setDao(UserDao dao) {
  31. this.dao = dao;
  32. }

}

  1. ```java
  2. public interface UserDao {
  3. void add();
  4. }
  1. package com.itheima.dao.impl;
  2. import com.itheima.dao.UserDao;
  3. public class UserDaoImpl implements UserDao {
  4. @Override
  5. public void add() {
  6. System.out.println("UserDaoImpl add...");
  7. }
  8. }
  1. 修改配置文件

    1. <!--
    2. set注入
    3. 1. 原理 : 空参构造 + set方法
    4. clazz = Class.forName("com.itheima.service.impl.UserServiceImpl3");
    5. service = class.newInstance(); //
    6. setName = clazz.getMethod("setName")
    7. setName.invoke(service,"zs");
    8. // service.setName("zs");
    9. 2. 配置 : bean标签内子标签property
    10. 1). name : bean中的属性名
    11. 2). 值
    12. value : 写基本类型和字符串
    13. ref: 引用类型
    14. -->
    15. <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
    16. <bean id="myDate" class="java.util.Date"/>
    17. <bean id="userService33" class="com.itheima.service.impl.UserServiceImpl3">
    18. <property name="name" value="zs"/>
    19. <property name="age" value="18"/>
    20. <property name="dao" ref="userDao"/>
    21. <property name="date" ref="myDate"/>
    22. </bean>
  1. 修改测试类
    1. @Test
    2. public void test05(){
    3. ApplicationContext ctx
    4. = new ClassPathXmlApplicationContext("applicationContext.xml");
    5. UserService service = (UserService) ctx.getBean("userService33");
    6. //zs,18,Tue Aug 10 15:32:32 CST 2021
    7. //UserDaoImpl add...
    8. service.save();
    9. }

zs,18,Tue Aug 10 15:32:32 CST 2021
UserDaoImpl add…

4.7)构造器注入(了解)

  • 名称:constructor-arg

  • 类型:标签

  • 归属:bean标签

  • 作用:使用构造方法的形式为bean提供资源,兼容早期遗留系统的升级工作

  • 格式:

    1. <bean>
    2. <!--有多少个参数,就有多少个标签-->
    3. <constructor-arg />
    4. </bean>
  • 基本属性:
    1. <constructor-arg name="argsName" value="argsValue" ref="refBeanName" />
    2. <!--value和ref属性只能二选一-->


name:对应bean中的构造方法所携带的参数名
value:设定非引用类型构造方法参数对应的值,不能与ref同时使用

其他属性:

  1. <constructor-arg index="arg-index" type="arg-type"/>
  1. type :设定构造方法参数的类型,用于按类型匹配参数或进行类型校验,配合value或者ref属性一块使用
  2. index :设定构造方法参数位置,用于按位置匹配参数,参数index值从0开始计数,,配合value或者ref属性一块使用
  • 注意:一个bean可以有多个constructor-arg标签
    代码演示

    1. 修改代码 ```java package com.itheima.service.impl;

import com.itheima.dao.UserDao; import com.itheima.service.UserService;

import java.util.Date;

public class UserServiceImpl4 implements UserService {

  1. private String name;
  2. private int age;
  3. private UserDao dao;
  4. private Date date;
  5. public UserServiceImpl4(String name, int age, UserDao dao, Date date) {
  6. this.name = name;
  7. this.age = age;
  8. this.dao = dao;
  9. this.date = date;
  10. }
  11. public void save() {
  12. System.out.println(name + "," + age + "," + date);
  13. dao.add();
  14. }

}

  1. 2.
  2. 修改配置文件
  3. ```xml
  4. <!--
  5. 构造器注入 (了解)
  6. 1. 原理
  7. clazz = Class.forName("com.itheima.service.impl.UserServiceImpl3");
  8. contructor = clazz.getConstructor(String.class,int.class,UserDao.class,Date.class);
  9. service = contructor.newInstance("zs",18,userDao,myDate);
  10. map.put("userService44",service);
  11. 2. 配置
  12. -->
  13. <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
  14. <bean id="myDate" class="java.util.Date"/>
  15. <bean id="userService44" class="com.itheima.service.impl.UserServiceImpl4">
  16. <constructor-arg name="name" value="zs"/>
  17. <constructor-arg name="age" value="18"/>
  18. <constructor-arg name="dao" ref="userDao"/>
  19. <constructor-arg name="date" ref="myDate"/>
  20. </bean>
  1. 修改测试类
    1. @Test
    2. public void test05(){
    3. ApplicationContext ctx
    4. = new ClassPathXmlApplicationContext("applicationContext.xml");
    5. UserService service = (UserService) ctx.getBean("userService44");
    6. //zs,18,Tue Aug 10 15:32:32 CST 2021
    7. //UserDaoImpl add...
    8. service.save();
    9. }

zs,18,Tue Aug 10 15:35:31 CST 2021
UserDaoImpl add…

4.8)集合类型数据注入(了解)

  • 名称:array,list,set,map,props

  • 类型:标签

  • 归属:property标签 或 constructor-arg标签

  • 作用:注入集合数据类型属性

  • 格式:

    1. <property>
    2. <list></list>
    3. </property>

(1)集合类型数据注入——list(掌握)

  1. <property name="al">
  2. <list>
  3. <value>itheima</value>
  4. <value>66666</value>
  5. </list>
  6. </property>

(2)集合类型数据注入——props(掌握)

  1. <property name="properties">
  2. <props>
  3. <prop key="name">itheima666</prop>
  4. <prop key="value">666666</prop>
  5. </props>
  6. </property>

(3)集合类型数据注入——array (了解)

  1. <property name="arr">
  2. <array>
  3. <value>123456</value>
  4. <value>66666</value>
  5. </array>
  6. </property>

(4)集合类型数据注入——set(了解)

  1. <property name="hs">
  2. <set>
  3. <value>itheima</value>
  4. <value>66666</value>
  5. </set>
  6. </property>

(5)集合类型数据注入——map(了解)

  1. <property name="hm">
  2. <map>
  3. <entry key="name" value="itheima66666"/>
  4. <entry key="value" value="6666666666"/>
  5. </map>
  6. </property>
  • 代码演示

    1. 修改代码 ```java package com.itheima.service.impl;

import com.itheima.service.UserService;

import java.util.*;

public class UserServiceImpl5 implements UserService {

  1. //前两个是重点
  2. private List<String> list;
  3. private Properties p;
  4. //了解
  5. private int[] array;
  6. private Set<String> set;
  7. private Map<String,String> map;
  8. public void save() {
  9. System.out.println("UserServiceImpl5 save...");
  10. System.out.println("list->" + list);
  11. System.out.println(list instanceof ArrayList);//true
  12. System.out.println("properties->" + p);
  13. System.out.println("array->" + Arrays.toString(array));
  14. System.out.println("set->" + set);
  15. System.out.println("map->" + map);
  16. }
  17. public List<String> getList() {
  18. return list;
  19. }
  20. public void setList(List<String> list) {
  21. this.list = list;
  22. }
  23. public Properties getP() {
  24. return p;
  25. }
  26. public void setP(Properties p) {
  27. this.p = p;
  28. }
  29. public int[] getArray() {
  30. return array;
  31. }
  32. public void setArray(int[] array) {
  33. this.array = array;
  34. }
  35. public Set<String> getSet() {
  36. return set;
  37. }
  38. public void setSet(Set<String> set) {
  39. this.set = set;
  40. }
  41. public Map<String, String> getMap() {
  42. return map;
  43. }
  44. public void setMap(Map<String, String> map) {
  45. this.map = map;
  46. }

}

  1. 2.
  2. 修改配置文件
  3. ```xml
  4. <!--
  5. # 集合类型数据注入
  6. 1. properties标签的name属性指定的是UserServiceImpl5中对应的属性名
  7. 2. properties的子标签
  8. 1). list : 声明该属性是List类型
  9. 2). props : 声明该属性是Properties类型
  10. 3). array : 声明该属性是数组类型
  11. 4). set : 声明该属性是Set类型
  12. 5). map : 声明该属性是Map类型
  13. 原理:
  14. clazz = Class.forName("com.itheima.service.impl.UserServiceImpl5")
  15. service = clazz.newInstance();
  16. setList = service.getMethod("setList",List.class);
  17. List list = new ArrayList();
  18. list.add("zs");
  19. list.add("ls");
  20. list.add("ww");
  21. setList.invoke(service,list);// service.setList(list)
  22. -->
  23. <bean id="userServiceImpl5" class="com.itheima.service.impl.UserServiceImpl5">
  24. <property name="list">
  25. <list>
  26. <value>zs</value>
  27. <value>ls</value>
  28. <value>ww</value>
  29. </list>
  30. </property>
  31. <property name="p">
  32. <props>
  33. <prop key="username">admin</prop>
  34. <prop key="password">123</prop>
  35. </props>
  36. </property>
  37. <property name="array">
  38. <array>
  39. <value>100</value>
  40. <value>200</value>
  41. </array>
  42. </property>
  43. <property name="set">
  44. <set>
  45. <value>ml</value>
  46. <value>qq</value>
  47. </set>
  48. </property>
  49. <property name="map">
  50. <map>
  51. <entry key="name" value="zhangsan"/>
  52. <entry key="age" value="18"/>
  53. </map>
  54. </property>
  55. </bean>
  1. 修改测试类
    1. @Test
    2. public void test06(){
    3. ApplicationContext ctx
    4. = new ClassPathXmlApplicationContext("applicationContext.xml");
    5. UserService service = (UserService) ctx.getBean("userServiceImpl5");
    6. service.save();
    7. }

UserServiceImpl5 save…
list->[zs, ls, ww]
true
properties->{password=123, username=admin}
array->[100, 200]
set->[ml, qq]
map->{name=zhangsan, age=18}

4.9)SpEL

el : expression language 表达式语言

总体含义: 都是数据引用

JSP: el表达式

mybatis : el表达式

  1. #{} / ${}

spring : el表达式

  1. #{} / ${}

js : el表达式

  1. `一共${money}元`
  • Spring提供了对EL表达式的支持,统一属性注入格式

  • 类型:属性值

  • 归属:value属性值

  • 作用:为bean注入属性值

  • 格式:

    1. <property value="EL"></bean>
  1. # springEL表达式
  2. 1. ${}
  3. ${} 用于加载外部文件指定的Key (在下一节课的properties文件中演示)
  4. 2. #{}
  5. #{} 强调的是把内容赋值给属性
  • 注意:所有属性值不区分是否引用类型,统一使用value赋值

  • 所有格式统一使用 value=“”

    • 常量 #{10} #{3.14} #{2e5} #{‘itcast’}

    • 引用bean #{beanId}

    • 引用bean属性 #{beanId.propertyName}

    • 引用bean方法 beanId.methodName().method2()

    • 引用静态方法 T(java.lang.Math).PI

    • 运算符支持 #{3 lt 4 == 4 ge 3}

    • 正则表达式支持 #{user.name matches‘[a-z]{6,}’}

    • 集合支持 #{myList[3]}

  • 代码演示:
    修改核心配置文件

    1. <!--
    2. value属性: 指定基本类型数据 (8大基本类型+String)
    3. ref属性: 指定的引用类型
    4. springEL
    5. 1. ${表达式}
    6. 引入配置文件中的数据
    7. 2. #{表达式}
    8. 强调的是把内容赋值给属性
    9. #{'字符串'}
    10. #{数字,boolean}
    11. #{变量名}
    12. -->
    13. <bean id="myDate" class="java.util.Date"/>
    14. <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
    15. <bean id="userService" class="com.itheima.service.impl.UserServiceImpl2">
    16. <!-- <property name="name" value="zs"/>
    17. <property name="age" value="18"/>
    18. <property name="date" ref="myDate"/>
    19. <property name="dao" ref="userDao"/>-->
    20. <property name="name" value="#{'ls'}"/>
    21. <property name="age" value="#{18}"/>
    22. <property name="date" value="#{myDate}"/>
    23. <property name="dao" value="#{userDao}"/>
    24. </bean>

4.10)properties文件

  • Spring提供了读取外部properties文件的机制,使用读取到的数据为bean的属性赋值

  • 操作步骤
    1.准备外部properties文件
    2.开启context命名空间支持

    1. xmlns:context="http://www.springframework.org/schema/context"


3.加载指定的properties文件

  1. <context:property-placeholder location="classpath:filename.properties"/>
  1. 4.使用加载的数据
  1. <property name="propertyName" value="${propertiesName}"/>
  • 注意:如果需要加载所有的properties文件,可以使用*.properties表示加载所有的properties文件

  • 注意:读取数据使用${propertiesName}格式进行,其中propertiesName指properties文件中的属性名

测试代码:

  1. 新增一个配置文件
    Spring-day01-课堂笔记 - 图13
    1. name=zs
    2. age=20
  1. public class UserServiceImpl implements UserService {
  2. //1. 声明需要注入的资源,并声明对应的set方法
  3. String name;
  4. int age;
  5. UserDao userDao;
  6. public void setName(String name) {
  7. this.name = name;
  8. }
  9. public void setAge(int age) {
  10. this.age = age;
  11. }
  12. public void setUserDao(UserDao userDao) {
  13. this.userDao = userDao;
  14. }
  15. @Override
  16. public void save() {
  17. System.out.println("UserServiceImpl run:" + name + "," + age);
  18. userDao.find();
  19. }
  20. }
  1. 配置文件修改

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <!--
    3. 1. schema约束新增: 开启context命名空间支持
    4. xmlns:context="http://www.springframework.org/schema/context"
    5. xsi:schemaLocation="http://www.springframework.org/schema/beans
    6. https://www.springframework.org/schema/beans/spring-beans.xsd
    7. http://www.springframework.org/schema/context
    8. https://www.springframework.org/schema/context/spring-context.xsd"
    9. -->
    10. <beans xmlns="http://www.springframework.org/schema/beans"
    11. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    12. xmlns:context="http://www.springframework.org/schema/context"
    13. xsi:schemaLocation="http://www.springframework.org/schema/beans
    14. https://www.springframework.org/schema/beans/spring-beans.xsd
    15. http://www.springframework.org/schema/context
    16. https://www.springframework.org/schema/context/spring-context.xsd
    17. ">
    18. <!--2. 加载指定的properties文件-->
    19. <context:property-placeholder location="classpath:data.properties"/>
    20. <bean id="userDao" class="com.itheima.ioc.dao.impl.UserDaoImpl"/>
    21. <!--
    22. 3. 使用加载的数据
    23. ${外部文件中的key}
    24. -->
    25. <bean id="userService" class="com.itheima.ioc.service.impl.UserServiceImpl">
    26. <property name="userDao" ref="userDao"/>
    27. <property name="name" value="${name}"/>
    28. <property name="age" value="${age}"/>
    29. </bean>
    30. </beans>
  1. 测试类修改

    1. public class UserTest {
    2. @Test
    3. public void test01(){
    4. //2.加载配置文件
    5. ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    6. //3.获取资源: 通过配置文件中的id
    7. UserService userService = (UserService) ctx.getBean("userService");
    8. userService.save();
    9. }
    10. }


打印结果:

UserServiceImpl run:zs,20
UserDao find…

总结

  1. # 思路
  2. 1. 哲学三问 : 是什么? 为什么? 怎么办?
  3. 2. 是什么 : 今天学了什么? 干什么用的? 好在哪里?
  4. 3. 为什么 : 原理
  5. 4. 怎么办 : 动手
  6. # 编程 (工科)
  7. 1. 理解 : 思想
  8. 1). 思想是诸多实践的提炼
  9. 2). 初级: 理解的不完全正确,都比不去理解好
  10. 2. 动手
  11. 1). 基于一知半解,动手,增进你的理解
  12. # 举个例子: Spring的IOC
  13. 1. IOC是什么? 控制反转...
  14. 干什么用的? 解耦
  15. DI:依赖注入
  16. IOCDI说得是同一件事,通俗来讲DI就是资源的需求方要被动等待IOC容器提供资源使用;
  17. 2. 原理
  18. 1). 直接创建对象
  19. 2). 面向接口编程 : 解耦左边
  20. 3).将new对象的公共代码封装到一个工具类中(工厂类)
  21. 4). 配置文件+反射 : 解耦右边
  22. -> 代码冗余
  23. 4). 工厂模式(容器) : 封装(工厂模式+反射+静态配置--》spring雏形)
  24. 3. 怎么办
  25. 1). 入门案例
  26. 2). 各种配置
  27. bean标签:
  28. 属性:
  29. id class scope init-mehtod destroy-method factory-method factory-bean lazy-init
  30. 子标签:
  31. set注入:<property name="xxx" value="xx" ref="xxxx">
  32. 如果属性是集合类型:
  33. list set array map props
  34. 构造器注入:<constructor-arg name="xxx" value="xx" ref="xxxx">
  35. 写两遍 (第一遍边看边写, 第二遍尽量自己写)

Maven注意点

maven设置

Spring-day01-课堂笔记 - 图14

Spring-day01-课堂笔记 - 图15

maven仓库的数据残留

用cleanLastUpdated.bat脚本程序,清理仓库中的残留jar包

重新刷新maven即可

idea创建工程

  1. # 学习阶段两个创建工程方案
  2. 1. 一天一个project
  3. 2. 一天一个module (推荐!!!)
  4. # 工程(project)和模块(module)
  5. 1. 一个project可以包含多个module
  6. 1). 一个project理论上是一个项目
  7. 2). 每个module是一个项目各个模块
  8. 2. A模块出问题了,B模块也运行不了
  9. # 创建方案(框架阶段)
  10. 1. 一个project : empty project
  11. 2. 每个案例一个module