SringBean的配置详解

image-20250122190215393

Bean的基础配置

  • 例如配置UserDaoImpl由Spring容器负责管理

    <bean id="userDao" class="com.nju.dao.impl.UserDaoImpl"/>

    此时存储到Spring容器(singleObjects单例池)中的Bean的beanName是userDao, 值是UserDaoImpl对象, 可以根据beanName获取Bean实例

    applicationContext.getBean("userDao");

    如果不配置id, 则Spring会把当前Bean实例的全限定名作为beanName

    applicationContext.getBean("com.nju.dao.impl.UserDaoImpl");

Bean的别名配置

  • 可以为当前Bean指定多个别名, 根据别名也可以获得Bean对象

    <bean id="userDao" name="aaa,bbb" class="com.nju.dao.impl.UserDaoImpl"/>

    此时多个名称都可以获得UserDaoImpl实例对象

    applicationContext.getBean("aaa");

    applicationContext.getBean("bbb");

Bean的范围配置

  • singleton: 单例, 默认值, Spring容器创建的时候, 就会进行Bean的实例化, 并存储到容器内部的单例池中, 每次getBean时都是从单例池中获取相同的Bean实例

  • prototype: 原型, Spring容器初始化时不会创建Bean实例, 当调用getBean时才会实例化Bean, 每次getBean都会创建一个新的Bean实例

Bean的延迟加载

  • lazy-init 设置为true时为延迟加载, 也就是当Spring容器创建的时候, 不会立即创建Bean实例, 等待用到时再创建Bean实例并存储到单例池中去, 后续在使用该Bean直接从单例池获取即可, 本质上该Bean还是单例的

    <bean id="userDao" class="com.nju.dao.impl.UserDaoImpl" lazy-init="true"/>

Bean的初始化和销毁方法配置

  • Bean在被实例化后,可以执行指定的初始化方法完成一些初始化的操作, Bean在销毁之前也可以执行指定的销毁方法完成一些操作

    <bean id="userDao" class="com.nju.dao.impl.UserDaoImpl" init-method="init" destory-method="destory"/>

  • 还可以通过实现InitializingBean接口, 完成一些Bean的初始化操作

Bean的实例化配置

  • 构造方式实例化: 底层通过构造方法对Bean进行实例化

    • 无参构造: Spring中配置的<bean>几乎都是

    • 有参构造: 需要参数注入

      1
      2
      3
      4
      // 有参构造方法
      public UserDaoImpl(String name) {
      ...
      }
      1
      2
      3
      <bean id="userDao" class="com.nju.dao.impl.UserDaoImpl">
      <constructor-arg name="name" value="haohao"/>
      </bean>
  • 工厂方式实例化: 底层通过调用自定义的工厂方法对Bean进行实例化

    • 静态工厂方法实例化Bean

      <bean id="userDao1" class="com.nju.factory.MyBeanFactory1" factory-method="userDao"/>

      不是把全限定名对应的类当作bean对象, 而是通过这个类中的 userDao 方法构造一个bean对象

      可以在Bean创建之前可以进行一些其他业务逻辑操作

    • 实例工厂方法实例化Bean

      <bean id="myBeanFactory2" class="com.nju.factory.MyBeanFactory2"/>

      <bean id="userDao2" factory-bean="myBeanFactory2" factory-method="userDao"/>

      先配置工厂对象bean, 再配置实例化对象bean

    • 实现FactoryBean规范延迟实例化Bean

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      public class MyBeanFactory3 implements FactoryBean<UserDao> {
      @Override
      public UserDao getObject() throws Exception {
      return new UserDaoImpl();
      }
      @Override
      public Class<?> getObjectType() {
      return UserDao.class;
      }
      }

      <bean id="myBeanFactory3" class="com.nju.factory.MyBeanFactory3"/>

      第一次调用的时候才会创建Bean, 得到的是工厂getObject方法返回的对象

Bean的依赖注入配置

image-20250122222740740

  • 对于想要注入的属性值或对象, 都要在类中有相应的set方法

  • 对于集合数据类型的注入

    1
    2
    3
    4
    5
    6
    7
    public class UserServiceImpl implements UsreService {
    // 注入List
    private List<String> stringList;
    public void setStringList(List<String> stringList) {
    this.stringList = stringList;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    <bean id="userService" class="com.nju.dao.impl.UserServiceImpl">
    <property name="stringList">
    <list>
    <value>aaa</value>
    <value>bbb</value>
    <value>ccc</value>
    </list>
    </property>
    </bean>

image-20250122224823006

Spring的其他配置标签

image-20250122225257947

image-20250122230153721

image-20250122230440099

image-20250122230558484

image-20250122231049114

Spring的get方法

image-20250123112444957

Spring配置非自定义Bean

image-20250123112649113

Bean实例化的基本流程

看源码

image-20250123175956461

image-20250123205224063

image-20250123205337808

Spring的后处理器

image-20250123205442348

BeanFactoryPostProcessor

  • 实现BeanFactoryProcessor接口, 重写postProcessBeanFactory方法进行后处理, 要在xml中配置到spring容器中, 会在适当时机自动调用方法

    可以在这里修改已有的bean, 或注册新的bean而不用配置在xml中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    // 注册BeanDifinition
    BeanDefinition beanDefinition = new RootBeanDefinition();
    // 设置全限定名
    beanDefinition.setBeanClassName("com.nju.dao.impl.PersonDaoImpl");
    // 强转成DefaultListableBeanFactory
    DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) beanFactory;
    // 注册到beanfactory中
    defaultListableBeanFactory.registerBeanDefinition("personDao", beanDefinition);
    }
    }

    但是上面的方式需要对beanFactory强转, 可以通过实现BeanFactoryProcessor接口的子类接口BeanDefinitionRegistryPostProcessor解决问题, 调用顺序是: 子类接口的postProcessBeanDefinitionRegistry -> 子类接口的postProcessBeanFactory -> 父类接口的postProcessBeanFactory

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    BeanDefinition beanDefinition = new RootBeanDefinition();
    beanDefinition.setBeanClassName("com.nju.dao.impl.PersonDaoImpl");
    registry.registerBeanDefinition("personDao", beanDefinition);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    // BeanDefinitionRegistryPostProcessor.super.postProcessBeanFactory(beanFactory);
    }
    }

image-20250123214138253

BeanPostProcessor

image-20250123215447888

image-20250123222717746

Spring Bean的生命周期

image-20250123222903961

  • Bean的初始化过程包括

    image-20250124182121238

    • Bean实例的属性填充

      • 注入普通属性时,直接通过set方法的反射设置进去

      • 注入单向对象引用属性时,从容器中getBean获取后通过set方法反射设置进去,若没有,则先创建被注入对象Bean实例

      • 注入双向对象引用属性(循环依赖)

        • 三级缓存解决该问题

          image-20250124194047815 image-20250124195020849

          下图为三级缓存源码剖析,可放大查看

          image-20250124195913441
    • Aware接口属性注入

      image-20250124211952361

    • BeanPostProcessor的before()方法回调

    • InitializingBean接口的初始化方法回调

    • 自定义初始化方法init回调

    • BeanPostProcessor的after()方法回调

Spring Ioc整体流程总结

image-20250124213735278

Spring xml方式整合第三方框架

  • 两种整合方案

    1. 不需要自定义名空间,不需要使用Spring的配置文件配置第三方框架本身内容,如:MyBatis
    2. 需要引入第三方框架命名空间,需要使用Spring的配置文件配置第三方框架本身内容,如:Dubbo