Spring加载Bean过程简析

1 定义bean的方式

常见的定义Bean的方式有:java

  • 经过xml的方式,例如:
<bean id="dictionaryRelMap" class="java.util.HashMap"/>
  • 经过注解的方式,在Class上使用@Component等注解,例如
@Component
public class xxxServicer{
    ....
}
  • 经过在@Configuration类下的@Bean的方式,例如
@Configuration
public class xxxConfiguration{
    @Bean
    public myBean myBean(){
        return new myBean();
    }
}

虽然这三种定义Bean的方式不同,对应的处理细节也不同,可是从大的逻辑上来看,都是同样。主要的流程以下图: 最关键的就是问题就是这么去找到定义Bean的方式,而后生成BeanDefinition后注册到Spring上下文中,由Spring自动建立Bean的实例。
输入图片说明spring

2 BeanDefinition

BeanDefinition是一个接口,用来描述一个Bean实例,例如是SINGLETON仍是PROTOTYPE,属性的值是什么,构造函数的参数是什么等。简单来讲,经过一个BeanDefinition咱们就能够完成一个Bean实例化。 BeanDefinition及其主要的子类:app

输入图片说明
下面简单说一下各个子类:ide

  • RootBeanDefinition和ChildBeanDefinition: 这2个BeanDefinition是相对的关系,自Spring 2.5 出来之后,已经被GenericBeanDefinition代替。由于这样强迫咱们在编写代码的时候就必须知道他们之间的关系。
  • GenericBeanDefinition: 相比于RootBeanDefinition和ChildBeanDefinition在定义的时候就必须硬编码,GenericBeanDefinition的优势能够动态的为GenericBeanDefinition设置parent。
  • AnnotatedBeanDefinition:看名字就是知道是用来读取经过注解定义Bean。

3 经过xml文件定义Bean

经过xml定义Bean是最先的Spring定义Bean的方式。所以,怎么把xml标签解析为BeanDefinition(), 入口是在org.springframework.beans.factory.xml.XmlBeanDefinitionReader这个类,可是实际干活的是在org.springframework.beans.factory.xml.BeanDefinitionParserDelegate。代码不少,但实际逻辑很简单,就是解析Spring定义的<bean> <property> 等标签 。 以前写过一篇文章介绍过如何自定义Spring标签 ,并解析后注册到Spring中——传送门函数

4 经过@Component等Spring支持的注解加载Bean

若是要使用@Component等注解定义Bean,一个前提条件是:有<context:component-scan/>或者@ComponentScan注解。但这2个方式仍是有一点点区别:post

4.1 context:component-scan/

因为<context:component-scan/>是一个xml标签,所以是在解析xml,生成的类org.springframework.context.annotation.ComponentScanBeanDefinitionParser,关键代码:编码

@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
        //获取base-package标签
	String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
	basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
	String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
			ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);

	// 实际处理类是ClassPathBeanDefinitionScanner 
	ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
    //扫描basePackage下全部的类,若是有@Component等标签就是注册到Spring中
	Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
	registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
	return null;
}

4.2 @ComponentScan

注解对应生成的类是org.springframework.context.annotation.ComponentScanAnnotationParser 其实最后实际干活的仍是ClassPathBeanDefinitionScanner这个。ComponentScanAnnotationParser类的生成是伴随着@Configuration这个注解处理过程当中(意思说@ComponentScan必须和@Configuration一块儿使用)。而处理@Configuration实际上是org.springframework.context.annotation.ConfigurationClassPostProcessor。是否是感受有点绕。
其实简单来讲,在处理@Configuration的时候发现有@ComponentScan注解,就会生成ComponentScanAnnotationParser去扫描@Component注解lua

4.3 ClassPathBeanDefinitionScanner

上面说到了,不管注解仍是标签的方式,最后都会交给ClassPathBeanDefinitionScanner这个类来处理,这个类作的就是1.扫描basePackage下全部class,若是有@Component等注解,读取@Component相关属性,生成ScannedGenericBeanDefinition,注册到Spring中。.net

5 经过@Bean方式

前面说了@ComponentScan是在@Configuration处理过程当中的一环,既然@Bean注解也是必须和@Configuration一块儿使用,那么说明@Bean的处理也是在@Configuration中,其实最后是交给ConfigurationClassBeanDefinitionReader这个类来处理的,关键代码:code

private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass,
		TrackedConditionEvaluator trackedConditionEvaluator) {

       //若是本身是经过@Import注解定义的,那么须要把本身注册到Spring中
	if (configClass.isImported()) {
		registerBeanDefinitionForImportedConfigurationClass(configClass);
	}
    //这里就是处理方法上的@Bean
	for (BeanMethod beanMethod : configClass.getBeanMethods()) {
		loadBeanDefinitionsForBeanMethod(beanMethod);
	}
    //处理@ImportResource,里面解析xml就是上面说到的解析xml的XmlBeanDefinitionReader
	loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
	loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

为了保证org.springframework.context.annotation.ConfigurationClassPostProcessor

6 把BeanDefinition实例化

前面分别说了怎么把不一样定义Bean的方式转换为BeanDefinition加入到Spring中去(确切来讲是保持在BeanFactory的BeanDefinitionMap中),实例是在ApplicationContext最后阶段,关键代码在DefaultListableBeanFactory中

@Override
	public void preInstantiateSingletons() throws BeansException {

		for (String beanName : beanNames) {
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				if (isFactoryBean(beanName)) {
					final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
					boolean isEagerInit;
					if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
						isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
							@Override
							public Boolean run() {
								return ((SmartFactoryBean<?>) factory).isEagerInit();
							}
						}, getAccessControlContext());
					}
					else {
						isEagerInit = (factory instanceof SmartFactoryBean &&
								((SmartFactoryBean<?>) factory).isEagerInit());
					}
					if (isEagerInit) {
						getBean(beanName);
					}
				}
				else {
					getBean(beanName);
				}
			}
		}

经过getBean最后最后实例的代码,在AbstractAutowireCapableBeanFactory中

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
        //处理xxAware接口
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged(new PrivilegedAction<Object>() {
				@Override
				public Object run() {
					invokeAwareMethods(beanName, bean);
					return null;
				}
			}, getAccessControlContext());
		}
		else {
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
            // 调用BeanPostProcessors#postProcessBeforeInitialization
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
           //初始化,先判断是不是InitializingBean,
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}

		if (mbd == null || !mbd.isSynthetic()) {
               // 调用BeanPostProcessors#postProcessAfterInitialization
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}
		return wrappedBean;
	}

从上面初始化能够看出,InitializeBean和BeanPostProcessors的调用顺序

7 总结

综上分析,Spring加载Bean其实大的思想都是同样的,先读取相关信息生成BeanDefinition,而后经过BeanDefinition初始化Bean。若是知道了上面了套路之后,就能够清楚怎么自定义Xml标签或者自定义注解向Spring中注入Bean。

相关文章
相关标签/搜索