spring 学习-bean创建-refresh前奏

概述

这篇文章我们将会 注解式生成bean的过程,总的来说就是 :

  1. 初始化一个Context
  2. 扫描生成 BeanDefinition
  3. 调用 refresh 方法 其中第一个步骤由于是注解类,利用第一步初始化生成的 Scan 类进行扫描特定包下的 bean ,然后根据属性,例如作用域,单例模式还是模板模式等属性生成 BeanDefinition ,最后调用 上下文 context 父类的refresh 方法,进行调用(BeanFactoryPostProcess)后置处理器处理方法和BeanPostProcess处理器处理方法。

例子1

    public static void main(String[] args) {
        AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext();
        //这里看到我们注册了一个 configuration 的类进行配置,然后刷新一下容器得到最新的结果
        consumerContext.register(ConsumerConfiguration.class);
        consumerContext.refresh();

        //从容器中获取类
        FooServiceConsumer service = consumerContext.getBean(FooServiceConsumer.class);

        ...

    }   

例子2

idea 中new一个新的 spring项目,然后编写两个类 。

@Component
public class MyService {
    public String sayHello(){
        return "hello world ";
    }


}


public class SpringTest {

    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext("main");//A
        MyService myService = ctx.getBean(MyService.class);
        String s = myService.sayHello();
        System.out.println("s : "+ s);
    }
}

我们以例子二为源码阅读,从 A 处 debug 进去,看一下 bean 的加载和创建

AnnotationConfigApplicationContext 的创建过程概述

构造方法很清晰 : 初始化,扫描,刷新三个步骤。

	public AnnotationConfigApplicationContext(String... basePackages) {
		//初始化
        this();
        //扫描包
		scan(basePackages);
        //刷新 
		refresh();
	}

源码分析

需要知道的类 :

  • Resoure 对应读取操作
  • BeanDefinitionRead 对应解析操作、
  • Registry 对应注册操作。

以 AnnotationConfigApplicationContext 为例子,查看类图主要包含三个类型的接口

  • AppContext : 上下文
  • Lifecycle : 生命周期
  • Registry : 用于注册 BeanDefinition

AnnotationConfigApplicationContext 的初始化创建的两个类作用如下 :

  • AnnotatedBeanDefinitionReader :注册几个后置处理器
  • ClassPathBeanDefinitionScanner :扫描包内的bean
	public AnnotationConfigApplicationContext(String... basePackages) {
        //初始化
		this();
        //扫描包
		scan(basePackages);
        //刷新 
		refresh();
	}


	/**
	 * Create a new AnnotationConfigApplicationContext that needs to be populated
	 * through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
     * 
     * 构造方法,从注释也可以看到,构造完,需要调用  register 方法进行填充和 refresh 方法进行刷新
	 */
	public AnnotationConfigApplicationContext() {
		this.reader = new AnnotatedBeanDefinitionReader(this);
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}


	//============ 父类初始化  ==============

    //==========================
	//GenericApplicationContext
	public GenericApplicationContext() {
		this.beanFactory = new DefaultListableBeanFactory();
	}


	//AbstractApplicationContext
	public AbstractApplicationContext() {
		this.resourcePatternResolver = getResourcePatternResolver();
	}


	//DefaultResourceLoader
	public DefaultResourceLoader() {
		this.classLoader = ClassUtils.getDefaultClassLoader();
	}

	public static ClassLoader getDefaultClassLoader() {
		ClassLoader cl = null;
		try {
			cl = Thread.currentThread().getContextClassLoader();
		}
		catch (Throwable ex) {
			// Cannot access thread context ClassLoader - falling back...
		}
		if (cl == null) {
			// No thread context class loader -> use class loader of this class.
			cl = ClassUtils.class.getClassLoader();
			if (cl == null) {
				// getClassLoader() returning null indicates the bootstrap ClassLoader
				try {
					cl = ClassLoader.getSystemClassLoader();
				}
				catch (Throwable ex) {
					// Cannot access system ClassLoader - oh well, maybe the caller can live with null...
				}
			}
		}
		return cl;
	}


	//============ 父类初始化  ==============

	//============ AnnotatedBeanDefinitionReader 类初始化  ==============

	
	public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		Assert.notNull(environment, "Environment must not be null");
		//保存父类字段
		this.registry = registry;
		//步骤一 : 用于解析 @Condition 注解相关
		this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
		//步骤二 : 最终会调用 register&registerBeanDefinition方法注册入几个默认的 BeanDefinition 
		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
	}

	


其中步骤二中注入的类包括 :

作用:内部托管配置注释处理器。
对应的类:ConfigurationClassPostProcessor.class

作用:内部管理的自动注入注解处理器
对应的类:AutowiredAnnotationBeanPostProcessor.class

作用:内部管理的JSR-250注释处理器
对应的类:CommonAnnotationBeanPostProcessor.class

作用:内部管理的JPA注释处理器(不一定注入)。
对应的类:PersistenceAnnotationBeanPostProcessor.class

作用:内部管理的@EventListener注释处理器
对应的类:EventListenerMethodProcessor.class

作用:内部管理的EventListenerFactory。
对应的类:DefaultEventListenerFactory.class

BeanDefinition 是个接口,我们看一下 ClassPathBeanDefinitionScanner 会扫描我们项目中的 bean

spring 学习-bean创建-refresh前奏

该类注解 : 

A bean definition scanner that detects bean candidates on the classpath, registering corresponding bean definitions with a given registry (BeanFactory or ApplicationContext).
Candidate classes are detected through configurable type filters. The default filters include classes that are annotated with Spring's @Component, @Repository, @Service, or @Controller stereotype.

下面我们看一下核心的scan 方法,它的调用栈挺长的,我们只需要知道scan 中会进行 :

  • 扫描所有 bean
  • 添加几个postprocess(后置处理器)作为 beanDefinition ,方便后续的
	

    @Override
	public void scan(String... basePackages) {
		Assert.notEmpty(basePackages, "At least one base package must be specified");
        //使用上面构造方法生成的 scan 对象,执行 scan 方法 
		this.scanner.scan(basePackages);
	}

	public int scan(String... basePackages) {
		int beanCountAtScanStart = this.registry.getBeanDefinitionCount();

		doScan(basePackages);

		// Register annotation config processors, if necessary.
		if (this.includeAnnotationConfig) {
			AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
		}

		return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
	}


	protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
		Assert.notEmpty(basePackages, "At least one base package must be specified");
		Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
		for (String basePackage : basePackages) {
			//这里会把配置文件中的 bean 读取出来,然后进行注册
			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
			for (BeanDefinition candidate : candidates) {
				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				candidate.setScope(scopeMetadata.getScopeName());
				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
				if (candidate instanceof AbstractBeanDefinition) {
					//为每个 BeanDefinition 填充作为 BeanDefinition 的属性值 
					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
				}
				if (candidate instanceof AnnotatedBeanDefinition) {
					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
				}
				//检查这个 BeanDefinition 是否一件存在,因为默认是单例,可以想象得到肯定是去 DefaultListableBeanFactory 中判断寻找
				if (checkCandidate(beanName, candidate)) {
					//封装成 BeanDefinitionHolder 对象
					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
					definitionHolder =
							AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
					beanDefinitions.add(definitionHolder);
					// register 注册  
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}
		}
		return beanDefinitions;
	}		



	protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
		BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
	}	

	//BeanDefinitionReaderUtils 类方法 
	public static void registerBeanDefinition(
			BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
			throws BeanDefinitionStoreException {

		// Register bean definition under primary name.
		String beanName = definitionHolder.getBeanName();
		//最终调用的是 registry 的 registerBeanDefinition 方法 
		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

		// Register aliases for bean name, if any.
		String[] aliases = definitionHolder.getAliases();
		if (aliases != null) {
			for (String alias : aliases) {
				registry.registerAlias(beanName, alias);
			}
		}
	}	

ok, scan 方法我们就了解这么多,下篇我们看一下 refresh方法。

总结

该篇文章我们介绍了 AnnotationConfigApplicationContext 的初始化过程,剩下的 refresh 方法将会留到下一篇文章进行讲解。

参考资料

  • https://blog.csdn.net/csdn_20150804 (spring5 系列分析)
  • https://juejin.im/post/5d7afbc6518825345a05c549 (小分析)
上一篇:Spring Boot 的启动流程 Run方法


下一篇:Spring IOC源码剖析:Spring IOC容器初始化主体流程