编程知识 cdmana.com

spring IOC加载流程

spring中最重要的概念是IOC和AOP,但是IOC总体来说有两处最重要,一个是创建Bean容器,一个是初始化Bean。

/**
*配置文件
*/
@Configuration
@ComponentSacn(basePackages = {""})
public class MainConfig{

}
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
//object 是自己注入的类,请自行添加
Object obj = context.getBean(Object.class);

以上面代码为例分析IOC的加载流程:

1、实例化容器:AnnotationConfigApplicationContext    

/**
*下面代码段为AnnotationConfigApplicationContext.java
*的一个构造方法
*/

//根据参数类型可以知道,其实可以传入多个annotatedClasses,但是这种情况出现的比较少  
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) { 
//调用无参构造函数,会先调用父类GenericApplicationContext的构造函数 
//父类的构造函数里面就是初始化DefaultListableBeanFactory,并且赋值给beanFactory 
//本类的构造函数里面,初始化了一个读取器:AnnotatedBeanDefinitionReader read,一个扫描器ClassPathBeanDefi nitionScanner scanner 
//scanner的用处不是很大,它仅仅是在我们外部手动调用 .scan 等方法才有用,常规方式是不会用到scanner对象的 

this(); 

//把传入的类进行注册,这里有两个情况, 
//传入传统的配置类 
//传入bean(虽然一般没有人会这么做)
//看到后面会知道spring把传统的带上@Configuration的配置类称之为FULL配置类,不带@Configuration的称之为Lite配置类 
//但是我们这里先把带上@Configuration的配置类称之为传统配置类,不带的称之为普通bean 

 register(annotatedClasses); 

//刷新 
refresh()

}

        这是一个有参的构造方法,可以接收多个配置类,不过一般情况下,只会传入一个配置类。

        这个配置类有两种情况,一种是传统意义上的带@Configuration注解的配置类,还有一种是没有带上@Configuration,但是带有@Component@Import,@ImportResource,@Service,@ComponentScan等注解的类,在Spring内部把前者称为Full配置类,把后者称为Lite配置类。有些地方也把Lite配置类称为普通bean。

        this()调用此类的无参构造方法,代码如下:

//注解bean定义的读取器,主要作用是用来读取被注解了的bean
private final AnnotatedBeanDefinitionReader reader;
//扫描器,它仅仅是在我们外部手动调用 .scan 等方法才有用,常规方法是不会用到 Scanner 对象的
private final ClassPathBeanDefinitonScanner scanner;

public AnnotationConfigApplicationContext(){
  //会隐式的调用父类的构造方法,初始化DefaultListableBeanFactory

  //初始化一个Bean读取器
  this.reader = new AnnotatedBeanDefinitionReader(this);
  
  //初始化一个扫描器,它仅仅是在我们外部手动调用 .scan 等方法时才用,常规方式是不会用到Scanner对象的
  this.scanner = new ClassPathBeanDefinitionScanner(this);

}

    首先无参构造方法就是对读取器 reader和扫描器scanner进行了实例化,reader类型就是AnnotatedBeanDefinitionReader,可以看出来这是一个打了注解的Bean定义读取器,scanner的类型是ClassPathBeanDefinitionScanner,它仅仅是在外面手动调用.scan方法,或者调用参数为String的构造方法,传入需要扫描的包名才会用到,像这样方式传入的配置类是不会用到这个scanner对象的。AnnotationConfigApplicationContext类是有继承关系的,会隐式的调用父类的构造方法。

2、实例化工厂:DefaultListableBeanFactory

/**
*代码继承关系
*代码结构
*/
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
//上文有提及
}

//GenericApplicationContext 的代码继承关系
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {

    private final DefaultListableBeanFactory beanFactory;

	@Nullable
	private ResourceLoader resourceLoader;

	private boolean customClassLoader = false;

	private final AtomicBoolean refreshed = new AtomicBoolean();

    /**
	 * Create a new GenericApplicationContext.
	 * @see #registerBeanDefinition
	 * @see #refresh
	 */
	public GenericApplicationContext() {
		this.beanFactory = new DefaultListableBeanFactory();
	}
}

    DefaultListableBeanFactory是相当重要的,从字面意思理解就可以看出他是一个Bean工厂,用来生产和获取Bean的。

3、实例化创建BeanDefinition读取器:AnnotatedBeanDefinitionReader

       主要做了两件事:

           3.1 注册内置的BeanPostProcessor

           3.2 注册相关的BeanDefinition

       spring在初始化AnnotatedBeanDefinitionReader的时候,如下代码

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry){
 this(registry,getOrCreateEnvironment(registry));
}

    这里BeanDefinitionRegistry当然就是AnnotationConfigApplicationContext的实例了,这里又直接调用了此类的其他构造方法:

public AnnotatedBeanDefinitionReader(BeanDefinitonRegistry registry,Environment environment){
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		Assert.notNull(environment, "Environment must not be null");
		this.registry = registry;
		this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);

}

    然后在看最后一行,进入registerAnnotationConfigProcessors(this.registry)方法:

/**
* Register all relevant annotation post processors in the given registry.
* 在给定的注册表中注册所有相关的注释后置处理器
* @param registry the registry to operate on
*/
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
	registerAnnotationConfigProcessors(registry, null);
}

    这又是一个门面方法,再点进去,这个方法返回的是Set,但是上游方法并没有去接收这个返回值,所以这个方法的返回值已经不重要了,当然方法内部给这个返回值赋值也不重要了。由于这个方法内容比较多,就把核心方法贴出来,这个核心的方法就是注册Spring内置的多个Bean:

/**
*1.判断容器中是否已经存在了ConfigurationClassPostProcessor Bean
*2.如果不存在(首次初始化肯定是不存在的),就通过RootBeanDefinition的构造方法获ConfigurationClassPostProcessor的BeanDefinition,
*RootBeanDefinition是BeanDefinition的子类
*3.执行registerPostProcessor方法,registerPostProcessor方法内部就是注册Bean,当然这里注册其他Bean也是一样的流程。
**/
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}

    BeanDefinition(接口)说明:向上继承BeanMetadataElement接口(BeanDefinition元数据,返回该Bean的来源)、AttributeAccessories接口(提供对Bean属性操作的能力),向下还有好多实现类,结构如下图:

BeanDefinition是用来描述Bean的,里面存放着关于Bean的一系列信息,比如Bean的作用域,Bean所对应的Class,是否懒加载,是否死Primary等等,这个BeanDefinition也相当重要。

/**
*registerPostProcessor方法为BeanDefinition设置了一个role,ROLE_INFRASTRUCTURE代表是spring内部的,并非用户
*定义的,然后又调用了registerBeanDefinition方法,点进去,就会发现是一个接口,没办法直接点进去了,首先要知道registry实现类是什么,这里是DefaultListableBeanFactory
*
**/
private static BeanDefinitionHolder registerPostProcessor(
			BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {

		definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		registry.registerBeanDefinition(beanName, definition);
		return new BeanDefinitionHolder(definition, beanName);
}

    点进去registerBeanDefinition方法,里面的核心代码在于下面两行代码:

//beanDefinitionMap是Map<String, BeanDefinition>
//这里就是把beanName作为key,ScopedProxyMode作为Value,放在map里
this.beanDefinitionMap.put(beanName, beanDefinition);
//beanDefinitionNames就是一个List<String>,这里就是把beanName放到list里面去
this.beanDefinitionNames.add(beanName);

从这里可以看出DefaultListableBeanFactory就是我们所说的容器了,里面放着BeanDefinitionMap,BeanDefinitionNames,BeanDefinitionMap就是一个hashMap,beanName作为key,BeanDefinition作为Value,beanDefinitionNames是一个集合,里面存放着beanName。(DefaultListableBeanFactory中的BeanDefinitionMap,beanDefinitionNames是相当重要的,后面经常用到,如果看到它,最好能第一时间就能知道它里面存放了什么数据。)这里仅仅是注册,可以简单的理解为把一些原料放入工厂,工厂还没有真正的去生产。上面已经介绍过,这里会一连串注册好几个bean,在这其中最重要的(没有之一)就是BeanDefinitionRegistryPostProcessor Bean。ConfigurationClassPostProcessor实现BeanDefinitionRegistryPostProcessor接口,BeanDefinitionRegistryPostProcessor接口又扩展了BeanFactoryPostProcessor接口,BeanFactoryPostProcessor是Spring的扩展点之一,ConfigurationClassPostProcessor是Spring极为重要的一个类。上述几个类之间的继承关系为:     

 除了注册ConfigurationClassPostProcessor,还注册了其他的Bean,其他Bean也都实现了其他接口,比如BeanPostProcess等。BeanPostProcessor接口也是Spring的扩展点之一。至此,实例化AnnotatedBeanDefinitionReader分析完毕。

4、创建BeanDefinition扫描器:ClassPathBeanDefinitionScanner

        由于常规的使用方式是不会用到AnnotationConfigApplicationContext里面的scanner的,这里的scanner仅仅是为了程序员可以手动调用AnnotationConfigApplicationContext对象的scan方法。这步可省略。

5、注册配置类为BeanDefinition:register(annotatedClasses)

    分析了实例化容器、实例化工厂、实例化BeanDefinition读取器,接下来分析register(annotatedClasses)方法。

    -------未完待续-------

6、refresh()

    6-5invokeBeanFactoryPostProcessors(beanFactory)

    6-11finishBeanFactoryLnitialization(beanFactory)

版权声明
本文为[李升鹏]所创,转载请带上原文链接,感谢
https://my.oschina.net/u/3211737/blog/4939308

Tags spring
Scroll to Top