Spring源码-IOC加载过程(注解方式加载)

Posted AC_Jobim

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring源码-IOC加载过程(注解方式加载)相关的知识,希望对你有一定的参考价值。

Spring源码-IOC加载过程(注解方式加载)

一、源码分析的入口

使用环境:SpringBoot2.1.16.RELEASE

  • Spring容器初始化入口,使用AnnotationConfigApplicationContext加载bean

    public static void main(String[] args)   
       // 加载spring上下文
       AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
    
       Car car =  context.getBean("car",Car.class);
       System.out.println(car.getName());
    
    

    MainConfig.class:

    @Configuration //作为配置类,替代 xml 配置文件
    @ComponentScan(basePackages = "com.zb.demo.spring")
    public class SpringConfig 
    
    
  • AnnotationConfigApplicationContext的构造方法

    //根据参数类型可以知道,其实可以传入多个annotatedClasses,但是这种情况出现的比较少
    public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) 
        //1、调用无参构造函数,会先调用父类GenericApplicationContext的构造函数,父类的构造函数里面就是初始化DefaultListableBeanFactory,并且赋值给beanFactory
        //2、本类的构造函数里面,初始化了一个读取器:AnnotatedBeanDefinitionReader read,一个扫描器ClassPathBeanDefinitionScanner scanner
        //scanner的用处不是很大,它仅仅是在我们外部手动调用 .scan 等方法才有用,常规方式是不会用到scanner对象的
        this();
        //3、把传入的类进行注册,这里有两个情况,
        //传入传统的配置类 和 传入bean(虽然一般没有人会这么做)
        //看到后面会知道spring把传统的带上@Configuration的配置类称之为FULL配置类,不带@Configuration的称之为Lite配置类
        //但是我们这里先把带上@Configuration的配置类称之为传统配置类,不带的称之为普通bean
        register(annotatedClasses);
        //刷新
        refresh();
    
    

    构造方法说明:

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

    • 这个配置类有两种情况,

      • 一种是传统意义上的带上@Configuration注解的配置类,
      • 另一种是没有带上@Configuration,但是带有@Component,@Import,@ImportResouce,@Service,@ComponentScan等注解的配置类,在Spring内部把前者称为Full配置类,把后者称之为Lite配置类。在本源码分析中,有些地方也把Lite配置类称为普通Bean

二、this()调用构造函数

调用AnnotationConfigApplicationContext类的无参构造方法

public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry 

    //注解bean定义读取器,主要作用是用来读取被注解的了bean
    private final AnnotatedBeanDefinitionReader reader;

    //扫描器,它仅仅是在我们外部手动调用 .scan 等方法才有用,常规方式是不会用到scanner对象的
    private final ClassPathBeanDefinitionScanner scanner;

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

        //初始化一个Bean读取器
        this.reader = new AnnotatedBeanDefinitionReader(this);

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

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

2.1 super()隐式调用父类的构造方法

  • 其中会隐式调用父类GenericApplicationContext的构造方法:实例化工厂DefaultListableBeanFactory

    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.
         */
    	public GenericApplicationContext() 
    		/**
    		 * 调用父类的构造函数,为ApplicationContext spring上下文对象初始beanFactory
    		 * 为啥是DefaultListableBeanFactory?我们去看BeanFactory接口的时候
    		 * 发现DefaultListableBeanFactory是最底层的实现,功能是最全的
    		 */
    		this.beanFactory = new DefaultListableBeanFactory();
    	
    
    

    问题: BeanFactory有很多, 为什么初始化的时候选择DefaultListableBeanFactory呢?

    DefaultListableBeanFactory的关系图:

    通过观察, 我们发现, DefaultListableBeanFactory实现了各种各样的BeanFactory接口, 同时还是先了BeanDefinitionRegistry接口。

    也就是说, DefaultListableBeanFactory不仅仅有BeanFactory的能力, 同时还有BeanDefinitionRegistry的能力. 它的功能是最全的。所以,我们使用的是一个功能非常强大的类Bean工厂类

2.2 初始化AnnotatedBeanDefinitionReader

this.reader = new AnnotatedBeanDefinitionReader(this);
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) 
   Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
   Assert.notNull(environment, "Environment must not be null");
   //把ApplicationContext对象赋值给AnnotatedBeanDefinitionReader
   this.registry = registry;
   //用户处理条件注解 @Conditional os.name
   this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
   //注册一些内置的后置处理器
   AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);

注册一些内置的后置处理器:AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
		BeanDefinitionRegistry registry, @Nullable Object source) 

	DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
	if (beanFactory != null) 
		if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) 
			//注册了实现Order接口的排序器
			beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
		
		//设置@AutoWired的候选的解析器:ContextAnnotationAutowireCandidateResolver
		// getLazyResolutionProxyIfNecessary方法,它也是唯一实现。
		//如果字段上带有@Lazy注解,表示进行懒加载 Spring不会立即创建注入属性的实例,而是生成代理对象,来代替实例
		if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) 
			beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
		
	

	Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

	/**
	 * 1.为我们容器中注册了解析我们配置类的后置处理器ConfigurationClassPostProcessor
	 * 名字叫:org.springframework.context.annotation.internalConfigurationAnnotationProcessor
	 */
	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));
	

	/**
	 * 2.为我们容器中注册了处理@Autowired 注解的处理器AutowiredAnnotationBeanPostProcessor
	 * 名字叫:org.springframework.context.annotation.internalAutowiredAnnotationProcessor
	 */
	if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) 
		RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
	

	/**
	 * 3.为我们容器注册处理JSR250规范的注解处理器CommonAnnotationBeanPostProcessor
	 * org.springframework.context.annotation.internalCommonAnnotationProcessor
	 */
	if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) 
		RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
	

	/**
	 * 4.处理jpa注解的处理器org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor
	 */
	if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) 
		RootBeanDefinition def = new RootBeanDefinition();
		try 
			def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
					AnnotationConfigUtils.class.getClassLoader()));
		
		catch (ClassNotFoundException ex) 
			throw new IllegalStateException(
					"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
		
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
	

	/**
	 * 5.处理监听方法的注解@EventListener解析器EventListenerMethodProcessor
	 */
	if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) 
		RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
	

	/**
	 * 6.注册事件监听器工厂
	 */
	if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) 
		RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
	

	return beanDefs;

在这里注册了6个后置处理器的Bean定义:

2.3 初始化bean定义扫描ClassPathBeanDefinitionScanner

this.scanner = new ClassPathBeanDefinitionScanner(this);
  • 创建BeanDefinition扫描器,可以用来扫描包或者类,进而转换为bd
  • Spring默认的扫描包不是这个scanner对象,而是自己new的一个ClassPathBeanDefinitionScanner,Spring在执行后置处理器ConfigurationClassPostProcessor时, 去扫描包时会new一个ClassPathBeanDefinitionScanner
  • 这里的scanner仅仅是为了程序员可以手动调用,AnnotationConfigApplicationContext对象的scan方法, 通过调用context.scan(“package name”);扫描处理配置类。

比如,可以这样使用:

public static void main(String[] args) 
   // 第一步: 通过AnnotationConfigApplicationContext读取一个配置类
   AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainStarter.class);
   context.scan("package name");
   Car car = (Car) context.getBean("car");
   System.out.println(car.getName());
   context.close();

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

register(annotatedClasses);

最终调用doRegisterBean(beanClass, null, null, null)方法将配置类注册成bean定义

<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
						@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) 
	//AnnotatedGenericBeanDefinition可以理解为一种数据结构,是用来描述Bean的,这里的作用就是把传入的标记了注解的类
	//转为AnnotatedGenericBeanDefinition数据结构,里面有一个getMetadata方法,可以拿到类上的注解
	AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);

	//判断是否需要跳过注解,spring中有一个@Condition注解,当不满足条件,这个bean就不会被解析
	if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) 
		return;
	

	abd.setInstanceSupplier(instanceSupplier);

	//解析bean的作用域,如果没有设置的话,默认为单例
	ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
	abd.setScope(scopeMetadata.getScopeName());

	//获得beanName
	String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

	//解析通用注解,填充到AnnotatedGenericBeanDefinition,解析的注解为Lazy,Primary,DependsOn,Role,Description
	AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);

	//限定符处理,不是特指@Qualifier注解,也有可能是Primary,或者是Lazy,或者是其他(理论上是任何注解,这里没有判断注解的有效性),如果我们在外面,以类似这种
	//AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Appconfig.class);常规方式去初始化spring,
	//qualifiers永远都是空的,包括上面的name和instanceSupplier都是同样的道理
	//但是spring提供了其他方式去注册bean,就可能会传入了
	if (qualifiers != null) 
		//可以传入qualifier数组,所以需要循环处理
		for (Class<? extends Annotation> qualifier : qualifiers) 
			//Primary注解优先
			if (Primary.class == qualifier) 
				abd.setPrimary(true);
			
			//Lazy注解
			else if (Lazy.class == qualifier) 
				abd.setLazyInit(true);
			
			//其他,AnnotatedGenericBeanDefinition有个Map<String,AutowireCandidateQualifier>属性,直接push进去
			else 
				abd.addQualifier(new AutowireCandidateQualifier(qualifier));
			
		
	

	for (BeanDefinitionCustomizer customizer : definitionCustomizers) 
		customizer.customize(abd);
	

	//这个方法用处不大,就是把AnnotatedGenericBeanDefinition数据结构和beanName封装到一个对象中
	BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);

	definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);

	//注册,最终会调用DefaultListableBeanFactory中的registerBeanDefinition方法去注册,
	//DefaultListableBeanFactory维护着一系列信息,比如beanDefinitionNames,beanDefinitionMap
	//beanDefinitionNames是一个List<String>,用来保存beanName
	//beanDefinitionMap是一个Map,用来保存beanName和beanDefinition
	BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);

在这里又要说明下,以常规方式去注册配置类,此方法中除了第一个参数,其他参数都是默认值。

  1. 通过AnnotatedGenericBeanDefinition的构造方法,获得配置类的BeanDefinition。
  2. 判断需不需要跳过注册,Spring中有一个@Condition注解,如果不满足条件,就会跳过这个类的注册。
  3. 然后是解析作用域,如果没有设置的话,默认为单例。
  4. 获得BeanName。
  5. 解析通用注解,填充到AnnotatedGenericBeanDefinition,解析的注解为Lazy,Primary,DependsOn,Role,Description。
  6. 限定符处理,不是特指@Qualifier注解,也有可能是Primary,或者是Lazy,或者是其他(理论上是任何注解,这里没有判断注解的有效性)。
  7. 把AnnotatedGenericBeanDefinition数据结构和beanName封装到一个对象中(这个不是很重要,可以简单的理解为方便传参)。
  8. 注册,最终会调用DefaultListableBeanFactory中的registerBeanDefinition方法去注册

四、refresh()

refresh()是 Spring 最核心的方法,没有之一,上帝就是用这个方法创造了 Spring 的世界。这是一个同步方法,用synchronized关键字来实现的。该方法包含以下12个核心方法。用来加载活刷新Spring配置,使配置生效

@Override
public void refresh() throws BeansException, IllegalStateException 
	synchronized (this.startupShutdownMonitor) 
		//1.准备刷新上下文环境
		prepareRefresh();

		//2.获取告诉子类初始化Bean工厂不同工厂不同实现
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		//还是一些准备工作,添加了两个后置处理器:ApplicationContextAwareProcessor,ApplicationListenerDetector
        //还设置了忽略自动装配和允许自动装配 的接口,如果不存在某个bean的时候,spring就自动注册singleton bean
        //还设置了bean表达式解析器等
		prepareBeanFactory(beanFactory);

		try 
			//4.留个子类去实现该接口
			postProcessBeanFactory(beanFactory);

			//5.调用我们的bean工厂的后置处理器. 1. 会在此将class扫描成beanDefinition  2.bean工厂的后置处理器调用
			invokeBeanFactoryPostProcessors(beanFactory);

			//6.注册我们bean的后置处理器
			registerBeanPostProcessors(beanFactory);

			//7.初始化国际化资源处理器.
			initMessageSource();

			//8.创建事件多播器
			initApplicationEventMulticaster();

			//9.这个方法同样也是留个子类实现的springboot也是从这个方法进行启动tomcat的.
			onRefresh();

			//10.把我们的事件监听器注册到多播器上
			registerListeners();

			//11.实例化我们剩余的单实例bean.
			finishBeanFactoryInitialization(beanFactory);

			//12.最后容器刷新 发布刷新事件(Spring cloud也是从这里启动的)
			finishRefresh();
		

		catch (BeansException ex) 
			if (logger.isWarnEnabled()) 
				logger.warn("Exception  encountered during context initialization - " +
						"cancelling refresh attempt: " + ex);
			

			// Destroy already created singletons to avoid dangling resources.
			destroyBeans();

			// Reset 'active' flag.
			cancelRefresh(ex);

			// Propagate exception to caller.
			throw ex;
		

		finally 
			// Reset common introspection caches in Spring's core, since we
			// might not ever need metadata for singleton beans anymore...
			resetCommonCaches();
		
	

4.1 prepareRefresh()

该方法用于容器刷新前的准备,包括设置上下文状态,获取属性,验证必要的属性等

// 设置启动时间
this.startupDate = System.currentTimeMillis();
// 1交给子类实现,初始化属性源
initPropertySources();
// 验证所有标记为必须的属性
getEnvironment().validateRequiredProperties();

4.2 obtainFreshBeanFactory()

该方法获取新的beanFactory。该方法很简单,刷新 BeanFactory 和获取 getBeanFactory

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() 
   refreshBeanFactory();
   return getBeanFactory();//返回我们的bean工厂,this()中new的工厂

4.3 prepareBeanFactory(beanFactory)

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) 
    // Tell the internal bean factory to use the context's class loader etc.
    beanFactory.谈谈Spring的IoC之注解扫描

Spring5源码分析(021)——IoC篇之bean加载

spring学习-IOC-配置驱动

spring学习-IOC-配置驱动

IoC 之 Spring 统一资源加载策略

Spring的IOC容器加载