首页 > 编程语言 >7.0 Spring启动过程源码解析

7.0 Spring启动过程源码解析

时间:2022-10-12 17:45:17浏览次数:47  
标签:ApplicationContext BeanFactory Spring Bean BeanFactoryPostProcessor 7.0 源码 BeanD

前言

一般来说,spring启动,就是构造ApplicationContext对象以及调用refresh()方法的过程

spring的启动主要做了这么几件事情:

  1. 构造一个BeanFactory对象
  2. 解析配置类,得到BeanDefinition,并注册到BeanFactory中
    • 解析@ComponentScan,此时就会完成扫描
    • 解析@Import
    • 解析@Bean
    • ...
  3. 因为ApplicationContext还支持国际化,所以还需要初始化MessageSource对象
  4. 因为ApplicationContext还支持事件机制,所以还需要初始化ApplicationEventMulticaster对象
  5. 把用户定义的ApplicationListener对象添加到ApplicationContext中,等Spring启动完了就要发布事件了
  6. 创建非懒加载的单例Bean对象,并存在BeanFactory的单例池中。
  7. 调用Lifecycle Bean的start()方法
  8. 发布ContextRefreshedEvent事件

由于Spring启动过程中要创建非懒加载的单例Bean对象,那么就需要用到BeanPostProcessor,所 以Spring在启动过程中就需要做两件事:

  1. 生成默认的BeanPostProcessor对象,并添加到BeanFactory中
    • AutowiredAnnotationBeanPostProcessor:处理@Autowired、@Value
    • CommonAnnotationBeanPostProcessor:处理@Resource、@PostConstruct、 @PreDestroy
    • ApplicationContextAwareProcessor:处理ApplicationContextAware等回调
  2. 找到外部用户所定义的BeanPostProcessor对象(类型为BeanPostProcessor的Bean对象), 并添加到BeanFactory中

BeanFactoryPostProcessor

Bean的后置处理器,是用来对Bean进行加工的,类似的, BeanFactoryPostProcessor理解为BeanFactory的后置处理器,用来用对BeanFactory进行加工的。

Spring支持用户定义BeanFactoryPostProcessor的实现类Bean,来对BeanFactory进行加工,比 如:

@Component
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
	@Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
    throws BeansException {
        BeanDefinition beanDefinition = beanFactory.getBeanDefinition("userService");
        beanDefinition.setAutowireCandidate(false);
    }
}

以上代码,就利用了BeanFactoryPostProcessor来拿到BeanFactory,然后获取BeanFactory内的某 个BeanDefinition对象并进行修改,注意这一步是发生在Spring启动时,创建单例Bean之前的,所 以此时对BeanDefinition就行修改是会生效的。

注意:在ApplicationContext内部有一个核心的DefaultListableBeanFactory,它实现了 ConfigurableListableBeanFactoryBeanDefinitionRegistry接口,所以ApplicationContext和 DefaultListableBeanFactory是可以注册BeanDefinition的,但是 ConfigurableListableBeanFactory是不能注册BeanDefinition的,只能获取BeanDefinition,然后 做修改。 所以Spring还提供了一个BeanFactoryPostProcessor的子接口: BeanDefinitionRegistryPostProcessor

BeanDefinitionRegistryPostProcessor

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor{
	void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}

BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor接口,并新 增了一个方法,注意方法的参数为BeanDefinitionRegistry,所以如果我们提供一个类来实现 BeanDefinitionRegistryPostProcessor,那么在postProcessBeanDefinitionRegistry()方法中就可 以注册BeanDefinition了。

public static void main(String[] args) {
        @Component
        public class ZhouyuBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
            @Override
            public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
                AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition()
                    .getBeanDefinition();
                beanDefinition.setBeanClass(User.class);
                registry.registerBeanDefinition("user", beanDefinition);
            }

            @Override
            public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
                BeanDefinition beanDefinition = beanFactory.getBeanDefinition("userService");
                beanDefinition.setAutowireCandidate(false);
            }
        }
    }

如何理解refresh()?

取自源码注释翻译:

加载或刷新持久化的配置,可能是XML文件、属性文件或关系数据库中存储的。由于这是一个启动方法,如果失败,它应该销毁已经创建的单例,以避免暂用资源。换句话说,在调用该方法之后,应该实例化所有的单例, 或者根本不实例化单例 。

ApplicationContext关闭之后不代表JVM也关闭了,ApplicationContext是 属于JVM的,说白了ApplicationContext也是JVM中的一个对象。

在Spring的设计中,也提供可以刷新的ApplicationContext和不可以刷新的ApplicationContext。

// 可以刷新
AbstractRefreshableApplicationContext extends AbstractApplicationContext
// 不可以刷新
GenericApplicationContext extends AbstractApplicationContext

AnnotationConfigApplicationContext继承的是GenericApplicationContext,所以它是不能刷新 的。 AnnotationConfigWebApplicationContext继承的是 AbstractRefreshableWebApplicationContext,所以它是可以刷的。 上面说的不能刷新是指不能重复刷新,只能调用一次refresh方法,第二次时会报错。

refresh()底层原理流程

面以AnnotationConfigApplicationContext为例子,来介绍refresh的底层原理。

  1. 在调用AnnotationConfigApplicationContext的构造方法之前,会调用父类 GenericApplicationContext的无参构造方法,会构造一个BeanFactory,为 DefaultListableBeanFactory
  2. 构造AnnotatedBeanDefinitionReader主要作用添加一些基础的PostProcessor,同时可以通过reader进行BeanDefinition的注册),同时对BeanFactory进行设置和添加 PostProcessor(后置处理器)
    • 设置dependencyComparator:AnnotationAwareOrderComparator,它是一个 Comparator,是用来进行排序的,会获取某个对象上的Order注解或者通过实现Ordered 接口所定义的值进行排序,在日常开发中可以利用这个类来进行排序。
    • 设置autowireCandidateResolver:ContextAnnotationAutowireCandidateResolver, 用来解析某个Bean能不能进行自动注入,比如某个Bean的autowireCandidate属性是否等 于true
    • 向BeanFactory中添加ConfigurationClassPostProcessor对应的BeanDefinition,它是 一个BeanDefinitionRegistryPostProcessor,并且实现了PriorityOrdered接口 i
    • 向BeanFactory中添加AutowiredAnnotationBeanPostProcessor对应的 BeanDefinition,它是一个InstantiationAwareBeanPostProcessorAdapter, MergedBeanDefinitionPostProcessor
    • 向BeanFactory中添加CommonAnnotationBeanPostProcessor对应的BeanDefinition, 它是一个InstantiationAwareBeanPostProcessor, InitDestroyAnnotationBeanPostProcessor
    • 向BeanFactory中添加EventListenerMethodProcessor对应的BeanDefinition,它是一个 BeanFactoryPostProcessor,SmartInitializingSingleton
    • 向BeanFactory中添加DefaultEventListenerFactory对应的BeanDefinition,它是一个 EventListenerFactory

标签:ApplicationContext,BeanFactory,Spring,Bean,BeanFactoryPostProcessor,7.0,源码,BeanD
From: https://www.cnblogs.com/ppku/p/16785399.html

相关文章

  • 6.0 Spring推断构造方法
    首先基础常识一个类通常有两个构造方法,一个有参的,一个无参的。对象创建默认使用无参构造。在spring中,只有一个无参的构造方法,那么实例化就只能使用这个无参构造。一、只......
  • 项目整合spring邮箱starter
    邮件发送的基本过程与概念(摘自小滴课堂大课)邮件服务器类似于现实生活中的邮局,它主要负责接收用户投递过来的邮件,并把邮件投递到邮件接收者的电子邮箱中电子邮箱:用户......
  • 关于 springcloud + nacos 启动报错:nacos save snapshot error
    关于nacos报错:nacossavesnapshoterror1:首先这个nacos报错并不影响你的正常使用,但是每次启动错误都会报错nacossavesnapshoterror,找不到config的配置;2:确......
  • 通过themyleaf模板显示spring-boot数据
    遍历后台返回数据,并动态生成表格 控制器返回ModelAndView前要指定视图名 在前端读取数据要用到的数据模型名要与后台返回时指定的名称一致 在用themyleaf模板前要在prope......
  • spring-boot 同时使用themyleaf和freemarker模板
    在pom中添加依赖 在templates目录中建立ftl文件与html文件 不同模板下调用方式如下:  ......
  • SpringCloud 微服务框架搭建
    框架及技术环境:IDEA、JDK1.8、MYSQL5.0、NacosServer2.1.1技术:SpringBoot+Nacos+SpringCloudGatway+SpringCloudOpenFegin+SpringSleuth+Maven目标用Maven搭建一个......
  • spring-boot配置属性注入到Bean
    1.在属性文件中配置book实体 2.创建配置属性对应实体类与控制器 3.输出实体时乱码在属性配置文件中加入spring.http.encoding.force=truespring.http.encoding.charset=UT......
  • Java 集合系列06之 Vector详细介绍(源码解析)和使用示例
    概要学完arrayList和LinkedList之后,我们接着学习Vector第1部分Vector介绍Vector简介Vector是矢量队列,它是JDK1.0版本添加的类。继承于AbstractList,实现了List,RandomAcce......
  • Java 集合系列03之 ArrayList详细介绍(源码解析)和使用示例
    概要上一章,我们学习了Collection的架构。这一章开始,我们对Collection的具体实现类进行讲解;首先,讲解List,而List中ArrayList又最为常用。因此,本章我们讲解ArrayList。先对Arra......
  • 视频直播源码,python实现列表插入、查找、删除
    视频直播源码,python实现列表插入、查找、删除#列表的插入、查找、删除实现 classTestArray:  def__init__(self,capacity)->None:    #由于python的lis......