为什么要用 Spring

为了解耦!

那么何为解耦?

耦合

指程序间的依赖关系:

  • 包括类之间的依赖

  • 包括方法之间的依赖

解耦

  • 降低程序间的依赖关系

  • 做到编译的时候不依赖(报错?),运行时才依赖。

思路

  • 用反射来创建对象。
  • 读取配置文件来读取要创建的对象的全限定类名。

IOC 容器详解

IOC: Inversion of Control

关键词:工厂模式,单例模式,线程安全。

  • 单例模式实现思路:新建静态 Map 共享 value 。

原来:

private IUserDao userDao = new UserDaoImpl();

IOC 实现:

private IUserDao userDao = (IUserDao) BeanFactory.getBean("userDao");

作用:控制反转,将控制权转移给 BeanFactory,从而割断与 Dao 层的直接联系,从而达到解耦。

注:以上的例子里,userDao 的新建对象任务已经交给了工厂。这样操作之后,编译时不会有依赖,但是运行时会有依赖。

IOC 的本质:把创建对象的权力交给框架。


Spring 中的 IOC

ApplicationContext 的三个常用实现类:

  • ClassPathXmlApplicationContext:加载类路径下的配置文件,必须要在类路径下,否则免谈。(常用)
  • FileSystemXmlApplicationContext:加载磁盘任意路径下的配置文件。
  • AnnotationConfigApplicationContext:用于读取注解容器。(常用)
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); // 运行这行时已经创建了对象。

IAccountService accountService = applicationContext.getBean("accountService", IAccountService.class);
IAccountDao accountDao = applicationContext.getBean("accountDao", IAccountDao.class);

或者用 BeanFactory 实现:

Resource resource = new ClassPathResource("applicationContext.xml");
BeanFactory beanFactory = new DefaultListableBeanFactory();
BeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader((BeanDefinitionRegistry) beanFactory);
beanDefinitionReader.loadBeanDefinitions(resource);

// 只有当创建了 Bean 之后才创建对象。
IAccountService accountService = beanFactory.getBean("accountService", IAccountService.class);
IAccountDao accountDao = beanFactory.getBean("accountDao", IAccountDao.class);

System.out.println("accountDao = " + accountDao);
System.out.println("accountService = " + accountService);
  • ApplicationContext 适用于单例对象,BeanFactory 适用于多例对象。
  • ApplicationContext 采用立即方式加载,BeanFactory 采用延迟方式加载。

Spring 中 Bean 的管理细节

创建 Bean 对象的三种方式

  1. 使用默认构造函数来创建Bean对象

    如果没有默认构造函数,则无法创建Bean对象

    <bean id="ClassId" class="ClassName"/>
    
  2. 用某个类中的方法创建对象并存入Spring容器

    <bean id="FactoryId" class="ClassName"/>
    <bean id="ClassId" factory-bean="FactoryBeanName" factory-method="MethodInFactory"/>
    
  3. 使用类中的静态方法创建对象并存入Spring容器

    <bean id="ClassId" class="FactoryName" factory-method="MethodInFactory"/>
    

Bean 对象的作用范围

对象默认为单例,如果要调整则更改scope参数。

<bean id="ClassId" class="ClassName" scope="singleton"/>

参数可以为:

  • singleton:单例(缺省值)
  • prototype:多例
  • request:web请求范围
  • session:web会话范围
  • global-session:集群环境的会话范围 - 负载均衡状况下产生的global-session

Bean 对象的生命周期

  1. 单例对象
    • 容器创建时对象产生
    • 容器存在时对象存在
    • 容器销毁时对象关闭
  2. 多例对象
    • 使用容器获得对象时产生
    • 只要没有关闭对象,对象就会存在
    • Java的垃圾回收机制

Spring 的依赖注入

依赖注入:Dependency Injection

我们将依赖关系的管理都交给 Spring。而我们所需要做的就是在配置文件中说明。


三种注入数据类型:

  1. 基本类型和 String

    直接填入value

  2. 其他 Bean 类型

    新建 Bean 并引用

    <bean id="ClassId" class="ClassName">
      <constructor-arg name="BeanName" ref="BeanId"/>
    </bean>
    
    <bean id="BeanId" class="BeanClassName"/>
    
  3. 复杂类型/集合类型

    <bean id="ClassId" class="ClassName">
      <property name="setName">
          <set>
              <value>AAA</value>
                <value>BBB</value>
                <value>CCC</value>
            </set>
        </property>
        <property name="listName">
          <list>
              <value>AAA</value>
                <value>BBB</value>
                <value>CCC</value>
            </list>
        </property>
        <!-- 除此之外还有 map array props 等等标签,其中 list set array 可以互换 map props 可以互换-->
    </bean>
    

三种注入方式:

  1. 使用构造函数

    使用的标签:constructor-arg

    其中的属性:

    • type

      指定类型

    • index

      指定参数索引的位置(从0开始)

    • name

      指定给构造函数中指定的参数赋值 (常用)

    • value

      提供基本类型或String类型的数据

    • ref

      其他Bean对象的 ID,在IOC中出现过的对象都可以

  2. 使用set方法(常用)

    使用的标签:property

    <bean id="ClassId" class="ClassName">
      <property name="[set]name" value="value"/>
    </bean>
    
  3. 使用注解:见笔记(二)


课程链接:

https://www.bilibili.com/video/BV1Sb411s7vP?from=search&seid=11893869544331926521