首页 归档 关于 learn love 工具

Spring 容器启动

重要类

  • BeanFactory: org.springframework.beans.factory.BeanFactory,是一个非常纯粹的 bean 容器,它是 IoC 必备的数据结构,其中 BeanDefinition 是它的基本结构。BeanFactory 内部维护着一个 BeanDefinition map ,并可根据 BeanDefinition 的描述进行 bean 的创建和管理。
  • BeanDefinition: org.springframework.beans.factory.config.BeanDefinition ,用来描述 Spring 中的 Bean 对象,如保存对象的类路径、对象的属性。
  • BeanFactoryPostProcessor, 当spring启动的时候,要执行容器的初始化,而BeanFactoryPostProcessor翻译过来就是bean工厂的后置处理器。简单来说,就是容器初始化完成之后,可以对容器做的一些后置处理。
  • BeanDefinitionRegistryPostProcessor , 此类为 BeanFactoryPostProcessor 子类,只不过BeanDefinitionRegistryPostProcessor支持动态注册beanDefinition,BeanFactoryPostProcessor原则上不支持
  • ApplicationContext: org.springframework.context.ApplicationContext ,这个是 Spring 容器,它叫做应用上下文,与我们应用息息相关。

生命周期

这里先说总结再讲解源码,先理清脉络再深入细节才不会迷失在细节当中。Spring的启动过程主要可以分为两部分:

  • 第一步:解析成BeanDefinition:将bean定义信息解析为BeanDefinition类,不管bean信息是定义在xml中,还是通过@Bean注解标注,都能通过不同的BeanDefinitionReader转为BeanDefinition类。
    • 这里分两种BeanDefinition,RootBeanDefintion和BeanDefinition。RootBeanDefinition这种是系统级别的,是启动Spring必须加载的6个Bean。BeanDefinition是我们定义的Bean。
  • 第二步:参照BeanDefintion定义的类信息,通过BeanFactory生成bean实例存放在缓存中。

入口

// 创建ioc容器, sMainConfig为配置类
ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
// AnnotationConfigApplicationContext
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
   // 读取注解的Bean定义读取器
   private final AnnotatedBeanDefinitionReader reader;
   // 扫描指定类路径中注解Bean定义的扫描器
   private final ClassPathBeanDefinitionScanner scanner;
   // 无参构造函数
   public AnnotationConfigApplicationContext() {
       // 查看new AnnotatedBeanDefinitionReader(this)源码可以发现
       // 此时往容器中注入了5个处理器
       // ConfigurationClassPostProcessor 这个内置的,唯一的实现了BeanDefinitionRegistryPostProcessor的后置处理器是解析其他通过注解注入的bean的类。
       // AutowiredAnnotationBeanPostProcessor 用来实现依赖注入的功能
       // CommonAnnotationBeanPostProcessor
       // EventListenerMethodProcessor
       // DefaultEventListenerFactory
       this.reader = new AnnotatedBeanDefinitionReader(this);
       this.scanner = new ClassPathBeanDefinitionScanner(this);
   }

   // 最常用的构造函数,通过将涉及的配置类传递给该构造函数,实现将相应配置类中的Bean自动注册到容器中
   public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
       // (1) 调用无参构造函数
       this();
       // (2) 将配置类信息封装成BeanDefinition对象保存到beanDefinitionMap容器中
       register(annotatedClasses);
       // (3)刷新容器,触发容器对注解Bean的载入、解析和注册
       refresh();
   }
}

初始化的过程可以看到初始化beanFactory为DefaultListableBeanFactory。这里可以看到AnnotationConfigApplicationContext虽然本身是一个beanFactory(实现了BeanFactory接口),但是依赖查找,依赖注入的过程是依赖内部的beanFactory来实现的(典型的代理模式)

另外需要注意的一点是,在容器初始化的过程中注册了6个Bean

  1. ConfigurationClassPostProcessor(实现了BeanFactoryPostProcessor,处理@Configuration)
  2. AutowiredAnnotationBeanPostProcessor(实现了BeanPostProcessor,处理@Autowired,@Value等)
  3. CommonAnnotationBeanPostProcessor(实现了BeanPostProcessor,用来处理JSR-250规范的注解,如@Resource,@PostConstruct等)
  4. PersistenceAnnotationBeanPostProcessor(实现了BeanFactoryPostProcessor,用来支持JPA,在我们这个Demo中不会注册,因为路径中没有JPA相关的类)
  5. EventListenerMethodProcessor(实现了BeanFactoryPostProcessor)
  6. DefaultEventListenerFactory

手动添加 BeanFactoryPostProcessor

首先我们要知道,给 Spring 容器提供 BeanFactoryPostProcessor 或者 BeanDefinitionRegistryPostProcessor 的 Bean 对象的方式有两种:

  • 通过加注解,让 Spring 扫描到类(把一个类交给 Spring 管理,整个类的创建过程是交给 Spring 来处理的),主要依赖上文提到的内置的 ConfigurationClassPostProcessor 进行扫描
  • 手动添加对象到 Spring 中(自己控制对象的实例化过程,然后再交给 Spring 管理)

手动注册BeanFactoryPostProcessor 并提供给 Spring 管理,是利用 ApplicationContext#addBeanFactoryPostProcessor api 进行 添加 ,例如

public class MyApplication {
	public static void main(String[] args) throws IOException {
		AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
		ctx.addBeanFactoryPostProcessor(new ManB());
		ctx.addBeanFactoryPostProcessor(new ManSubY());
		ctx.register(AppConfig.class);
		ctx.refresh();
	}
}

BeanFactoryPostProcessors执行顺序

Spring容器注册bean方式

常见注册bean对象到spring容器的方式:

  • @Component、@Controller、@Service、@Repository 方式,此为自动创建

  • @Bean 方式,配置类方法加上 @Bean 注解

  • @Import 方式

    • @Import 普通类
    • @Import ImportSelector
    • @Import ImportBeanDefinitionRegistrar
  • 实现 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry

  • FactoryBean接口
    以上,都是需要ConfigurationClassPostProcessor 这个内置 BeanDefinitionRegistryPostProcessor 进行扫描,然后加载

  • XML配置文件:通过在XML配置文件中使用标签来定义和注册bean。

番外

动态地给Java对象添加字段并赋值,并不是在已经实例化的对象上去完成的。基于cglib,commons-beanutils库实现思路为:

  1. 将原对象和扩展字段封装为字段map
  2. 基于字段map和原对象创建其子类对象
  3. 重新将原字段值和扩展字段值赋给子类对象
  4. 返回子类对象

相当于是复制类定义,然后新建个类定义处理。和 spring 的在 BeanFactoryPostProcessor 中添加属性是相通的,因为此时还没对bean进行实例化。

参考

  • https://www.cnblogs.com/JaxYoun/p/13923703.html
  • https://juejin.cn/post/7238200443581677625
  • https://learnku.com/articles/42527
  • https://www.cnblogs.com/kendoziyu/p/springframework-bean-factory-post-processor.html
  • https://juejin.cn/post/7039308644768284679