2019年个人总结-Spring IOC初始化流程

只愿大浪淘沙,流逝不流它

首先说一下个人对spring容器(spring官网所有项目里面有一个项目叫spring springframework 简称spring框架)的理解

spring框架是一个容器,是用来存放我们交给spring管理的对象简称bean的容器。

核心模块主要分为IOC 和 AOP(web ,test 等等)

IOC 也叫DI 控制反转和依赖注入。主要思想就是解耦,控制反转主要是说我们以前需要程序员通过new 关键字创建一个对象并且维护各对象之间的依赖关系,那么有了IOC以后我们只需要将这个对象交给容器就行了,它会帮我们创建以及维护对象之间的依赖关系。

而AOP呢,面向切面编程,将我们项目中公共模块分离封装成一个单独的模块这个模块称之为切面,在思想上也是为了解耦而生的。

我们使用aop有两种方式,第一种是通过xml文件配置的spring aop,第二种是通过注解@Aspect来开启的。

我们一个切面里面应该有连接点(表达式 execution ,within等等),切点,通知(之前,之后,环绕,异常),织入。

区别呢就是spring aop 属于运行时动态织入的。而Aspect是编译时静态织入的。看个人爱好使用哪一种

那么AOP呢是依赖于IOC的,与其说IOC 和 AOP是两个部分(官网分开了),不如说AOP是IOC的一部分,因为springbean的生命周期中伴随了AOP的解析(比如第一步就通过了BeanPostProcessor的一个后置处理器来填充需要代理的对象集合来准备后期的增强)。

 首先想引入的一点是 BeanDefinition 这个对象,Spring最终的目的就是将Java Object ---> BeanDefinition ---> Spring Bean

 的过程,所以 BeanDefinition 这个对象和它的属性及子类非常重要。再次引入spring官网的这张图片

Java Object 通过 Spring 容器 填充元属性后 变成一个 BeanDefinition 对象 后再经过一整个生命周期的过程 变成 一个 Spring Bean 提供给你使用,其中的过程与实现无须我们动手。

引入的第二点就是Spring 容器的扩展点。

扩展点如下

InitializingBean Spring Bean 生命周期回调接口之一 Spring Web MVC 初始化填充Map属性就是实现了该接口 

SmartLifecycle Spring 容器初始化完成回调接口之一 

ImportSelector Spring Boot的自动配置(非Spring 的自动装配)实现了该接口

ImportBeanDefinitionRegistrar MyBatis 整合 Spring 实现了该接口 扫描MapperScanner属性的接口-->代理对象-->Spring                                                     Bean的过程

BeanFactoryPostProcessor BeanFactory工厂后置处理器

BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor  BeanFactory工厂后置处理器

ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor BeanFactory工厂后置处理器内置唯                                                                                                                                          一实现类
接下来在源码中看下这三个类(实现类)的执行时机

new AnnotationConfigApplicationContext(AppConfig.class);
this();//第一步 初始化 beanFactory 工厂
register(annotatedClasses); // 注册配置类
refresh(); // 如下 
//准备工作包括设置启动时间,是否激活标识位,初始化属性源(property,source)配置
prepareRefresh();
//获取到 DefaultListableBeanFactory 对象
//已经注册过了
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//传入 beanFactory 调用处理器对Bean工厂做一些标准的配置
prepareBeanFactory(beanFactory);
//空方法
postProcessBeanFactory(beanFactory);
//执行自定义的BeanFactoryProcessor和内置的BeanFactoryProcessor
// 完成扫描和解析 object --  > beanDefinition
invokeBeanFactoryPostProcessors(beanFactory);//开始执行BeanFactory的后置处理器扩展点(策略模式)
registerBeanPostProcessors(beanFactory);//开始执行BeanFactory 的后置处理器
initMessageSource();
initApplicationEventMulticaster();
onRefresh();
registerListeners();
//实例化所有的非懒加载单例
//bean生命周期
finishBeanFactoryInitialization(beanFactory);
finishRefresh();

invokeBeanFactoryPostProcessors(beanFactory);

实现这个接口的 BeanDefinitionRegistryPostProcessor BeanFactory的后置处理器执行时机

1.先执行实现 BeanDefinitionRegistryPostProcessor 和 PriorityOrdered 的接口 的BeanFactory的后置处理器

2.再执行实现 BeanDefinitionRegistryPostProcessor 和 Ordered 的接口 的BeanFactory的后置处理器

3.最后执行实现 BeanDefinitionRegistryPostProcessor 的接口 的BeanFactory的后置处理器

实现这个接口的 BeanFactoryPostProcessor BeanFactory的后置处理器执行时机

4.先执行实现 BeanFactoryPostProcessor 和 PriorityOrdered 的接口 的BeanFactory的后置处理器

5.再执行实现 BeanFactoryPostProcessor 和 Ordered 的接口 的BeanFactory的后置处理器

6.最后执行实现 BeanFactoryPostProcessor 的接口 的BeanFactory的后置处理器

在执行这些 BeanFactory 的后置处理器的时候 Spring还会执行一个Bean的后置处理器主要是完成父子BeanDefinition的合并,所以引入的第一点很重要。

ConfigurationClassPostProcessor 实现 BeanDefinitionRegistryPostProcessor 后置处理器 Spring 做了什么

完成二次扫描解析配置类包含的所有注解@Import  @PropertySource @ComponentScans @Bean

和实现了ImportSelector  接口及实现了ImportBeanDefinitionRegistrar 接口的类

封装成 BeanDefinition 并注册到 BeanDefinitionMap 中。

ConfigurationClassPostProcessor 实现 BeanFactoryPostProcessor 后置处理器 Spring 做了什么

主要为配置类完成CGLIB增强 我们看下面

@ComponentScan("org.springframework.test2")
@Configuration
public class AppConfig {
   
   @Bean
   public B b(){
      System.out.println("===b===");
      return new B();
   }

   @Bean
   public  A a(){
      System.out.println("===a===");
      b();
      return new A();
   }

}

为什么加了@Configuration这个注解只会打印一次 a 和 b 而不加会打印两次 b 呢。

对象a 和 对象b都是单例的,为什么会初始化两次b呢

加了@Configuration这个注解 会被 ConfigurationClassPostProcessor 类解析并进行CGLIB代理。

但为什么进行CGLIB之后b就只会被初始化一次呢(Spring循环依赖原理)

 registerBeanPostProcessors(beanFactory);

实现这个接口的 BeanPostProcessor Bean的后置处理器执行时机是伴随着Bean的生命周期

1.先添加实现 BeanPostProcessor 和 PriorityOrdered 的接口 的Bean的后置处理器

2.再添加实现 BeanPostProcessor 和 Ordered 的接口 的Bean的后置处理器

3.最后添加实现 BeanPostProcessor 的接口 的Bean的后置处理器

Bean的后置处理器执行时机

1.判断正在实例化的Bean是否需要被代理,如果需要就添加到一个集合中并返回空

InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation{return null}

2.推断构造方法

SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors{return null}

spring-ioc-推断构造函数-手动装配  spring-ioc-推断构造函数-自动装配

3.合并父子BeanDefinition

MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition

4.循环依赖,暴露一个工厂,通过工厂去获取Bean的实例(暴露工厂的原因是为代理对象装配属性)SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference

spring-ioc-循环依赖

5.属性注入,判断当前对象是否允许属性注入(默认为true)InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation

6.属性注入 手动注入@Autowired和@Resource 基于Java反射机制 自动注入(注入模型之一)基于Java内省机制

源码中关于@Autowired和@Resource 的查找方式 @Autowired先根据type找,将找到的类型放到一个集合中,然后在集合中通过name去匹配,反之 @Resource

为什么@Autowired和@Resource不属于自动注入请看

spring-ioc-自动装配

7.执行Aware接口,和我们自己实现了BeanPostProcessor的Before方法

BeanPostProcessor#postProcessBeforeInitialization

8.动态代理Proxy,和我们自己实现了BeanPostProcessor的After方法

BeanPostProcessor#postProcessAfterInitialization

执行Bean生命周期回调有三种方式

第一,初始化回调。三种都可以存在 执行顺序 注解>接口>xml

第一种 基于 xml 的 <bean init-method="">

第二种 基于 接口 实现了InitializingBean

第三种 基于 注解 @PostConstruct

同理 销毁回调

<bean destroy-method="">  

DestroyBean implements DisposableBean

@PreDestroy

执行Spring 容器生命周期回调

实现了 SmartLifecycle 接口的类 和实现了 Lifecycle 接口的类

interface Lifecycle{

void start();

void stop();

boolean isRunning();

}

interface SmartLifecycle {

isAutoStartup();

void stop(Runnable callback);

int getPhase();

}

至此Spring Bean的生命周期结束 Spring 容器的初始化完成

总结一点就是两部分

第一部分 BeanFactoryPostProcessor  BeanFactory的后置处理器完成Spring 容器的初始化的一半

第二部分BeanPostProcessor Bean的后置处理器完成Spring 容器的初始化的另一半及Bean的生命周期

猜你喜欢

转载自blog.csdn.net/qq_38108719/article/details/103384787