Spring源码分析 为什么xml定义的bean优先于注解定义的bean ?

    spring大家都再熟悉不过了,功能十分强大,个人感觉对Java语言推进最大的两个部分一个是Jdk5的concurrent包还有就是Spring.
concurrent工具类的推出,对java并发编程的提升是巨大的,目前java很多优秀的中间件比如netty都是在它的基础上开发出来的;
spring的推出,提升了项目开发和管理的效率, 现在主流的项目都是采用的spring, 它以一己之力改变了传统的J2EE企业开发方式.
spring中我们最熟悉的,也是打交道最多的就是spring的xml和注解,xml和注解让我们用配置的方式代替以前的硬编码,从而不同的对象解耦开来.

针对xml和注解有一个问题:

  • 在Spring的xml中申明一个bean,java代码中再用注解(@componet等)申明一个bean,两个bean的id和class都一样, 最终生效的有几个bean?
  • 如果生效的只有一个bean, 那种方式生成的bean有效, 也就是哪一种方式的优先级更高?
  • 为什么?
下面我们就以这个问题作为切入点和主线分析下Spring源码, 详细看下整个代码流程:

1. AbstractApplicationContext.java
这是Spring容器启动时,加载所有配置和维护庞大的bean的关系网的入口类,入口方法就是refresh(),这里是refresh的主要流程解释.
public void refresh() throws BeansException, IllegalStateException {

	synchronized (this.startupShutdownMonitor) {
		// Prepare this context for refreshing.
		// 就是初始化Spring中的一些properties配置到内存中,和准备运行环境等
		prepareRefresh();

		// Tell the subclass to refresh the internal bean factory.
		// 就是获取一个新的工厂,
		// obtainFreshBeanFactory()内部的执行顺序: ==> refreshBeanFactory() ==> loadBeanDefinitions(beanFactory) 
		// obtainFreshBeanFactory()方法会将xml中的配置bean都加载到内存中,后续的finishBeanFactoryInitialization创建bean时会用到.
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		// Prepare the bean factory for use in this context.
		// 准备BeanFactory
		prepareBeanFactory(beanFactory);

		try {
			// Allows post-processing of the bean factory in context subclasses.
			// 后处理BeanFactory,注册了几个BeanPostProcessor?
			postProcessBeanFactory(beanFactory);

			// Invoke factory processors registered as beans in the context.
			// 主要是获取实现了 BeanFactoryPostProcessor的子类, 并执行postProcessBeanFactory方法
			invokeBeanFactoryPostProcessors(beanFactory);

			// Register bean processors that intercept bean creation.
			// 主要就是注册bean创建的前置和后置处理器 processers
			registerBeanPostProcessors(beanFactory);

			// Initialize message source for this context.
			initMessageSource();

			// Initialize event multicaster for this context.
			// 初始化spring里的时间广播
			initApplicationEventMulticaster();

			// Initialize other special beans in specific context subclasses.
			// 一个空的方法,用来给子类扩展的
			onRefresh();

			// Check for listener beans and register them.
			// 注册时间监听器
			registerListeners();

			// Instantiate all remaining (non-lazy-init) singletons.
			// 实例化所有非懒加载的单例Bean (根据前面loadBeanDefinitions(beanFactory) 维护的全量的 BeanDefinition 创建Bean并且缓存下来)
			finishBeanFactoryInitialization(beanFactory);

			// Last step: publish corresponding event.
			// 发布时间通知等
			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.
			// 抛出异常,在关闭容器前,回收前面创建的bean
			destroyBeans();

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

			// Propagate exception to caller.
			throw ex;
		}
	}
}

2. refresh()方法里的obtainFreshBeanFactory()方法
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
	refreshBeanFactory();				//刷新工厂, 清理老的内容, 创建一个崭新的beanFactory
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	if (logger.isDebugEnabled()) {
		logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
	}
	return beanFactory;
}

3. obtainFreshBeanFactory方法里第一行的refreshBeanFactory()方法:
protected final void refreshBeanFactory() throws BeansException {
	if (hasBeanFactory()) {							//已经存在beanFactory就摧毁beans,关闭beanFactory
		destroyBeans();
		closeBeanFactory();
	}
	try {
		DefaultListableBeanFactory beanFactory = createBeanFactory();	//创建一个崭新的beanFactory (DefaultListableBeanFactory)
		beanFactory.setSerializationId(getId());
		customizeBeanFactory(beanFactory);
		loadBeanDefinitions(beanFactory);				//加载xml文件里面定义的各种Bean到beanFactory中
		synchronized (this.beanFactoryMonitor) {
			this.beanFactory = beanFactory;
		}
	}
	catch (IOException ex) {
		throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
	}
}
方法里的loadBeanDefinitions(beanFactory),会把开发者定义的xml里的各种bean注册到beanFactory中,
我们在xml里面用<bean .../>标签定义的正常的beanDefinition都是在这里解析加载的;
有一类特殊的标签, 例如<context: .../> 这是在spring自定义的标签,用于做特殊处理的
解析这种标签需要spring.handlers配置文件的帮助, spring.handlers里面定义了各种自定义标签和对应的处理器.

spring-context模块的spring.handlers如下:

http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler
http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler
http\://www.springframework.org/schema/task=org.springframework.scheduling.config.TaskNamespaceHandler
http\://www.springframework.org/schema/cache=org.springframework.cache.config.CacheNamespaceHandler

context标签对应的是org.springframework.context.config.ContextNamespaceHandler, 这个类继承了NamespaceHandlerSupport,
NamespaceHandlerSupport的org.springframework.beans.factory.xml.NamespaceHandlerSupport#parse方法是用来解析自定义的标签的,
里面又调用了org.springframework.context.annotation.ComponentScanBeanDefinitionParser#parse方法,
最终调用到这里org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan (详细见下面代码)

/**
 * Perform a scan within the specified base packages,
 * returning the registered bean definitions.
 * <p>This method does <i>not</i> register an annotation config processor
 * but rather leaves this up to the caller.
 * @param basePackages the packages to check for annotated classes
 * @return set of beans registered if any for tooling registration purposes (never {@code null})
 */
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
	Assert.notEmpty(basePackages, "At least one base package must be specified");
	Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
	for (String basePackage : basePackages) {
		Set<BeanDefinition> candidates = findCandidateComponents(basePackage);	//找到所有的注解了@component或者注解标记了@component的注解 (@component就是spring的元注解)
		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) {
				postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
			}
			if (candidate instanceof AnnotatedBeanDefinition) {
				AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
			}
			if (checkCandidate(beanName, candidate)) { //判断两个beanDefinition是否冲突,实际就是在这里处理xml和注解bean冲突的,继续往方法里面看
				BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
				definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
				beanDefinitions.add(definitionHolder);
				registerBeanDefinition(definitionHolder, this.registry);
			}
		}
	}
	return beanDefinitions;
}

4. 方法checkCandidate会处理冲突, 关键就在其中的isCompatible(beanDefinition, existingDef)方法
// 入参beanName是注解Bean的beanName; beanDefinition是注解bean的beanDefinition
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
	if (!this.registry.containsBeanDefinition(beanName)) {				//判断beanName还没有被注册过,直接返回true
		return true;
	}
	BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);		//existingDef是已经注册了的beanDefinition
	BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();	//如果originatingDef不为空,那么existingDef就只是一个装饰器,需要找到原始的.
	if (originatingDef != null) {							//在我们这个问题中,这里originatingDef为null.
		existingDef = originatingDef;
	}
	if (isCompatible(beanDefinition, existingDef)) {	//判断两个beanDefinition是否兼容; 不兼容就返回false.
		return false;
	}
	throw new ConflictingBeanDefinitionException("Annotation-specified bean name '" + beanName +
			"' for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " +
			"non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]");
}

5. isCompatible(beanDefinition, existingDef)方法;
/**
 * Determine whether the given new bean definition is compatible with			//判断newDefinition是否和existingDefinition兼容
 * the given existing bean definition.
 * <p>The default implementation considers them as compatible when the existing		//只要两个都不是scanning source(也就是都不是通过scan 注解生成的)
 * bean definition comes from the same source or from a non-scanning source.		//并且(the same source)来源相同就认为他们是兼容的
 * @param newDefinition the new bean definition, originated from scanning
 * @param existingDefinition the existing bean definition, potentially an
 * explicitly defined one or a previously generated one from scanning
 * @return whether the definitions are considered as compatible, with the
 * new definition to be skipped in favor of the existing definition
 */
protected boolean isCompatible(BeanDefinition newDefinition, BeanDefinition existingDefinition) {
	return (!(existingDefinition instanceof ScannedGenericBeanDefinition) ||  	 // explicitly registered overriding bean
			newDefinition.getSource().equals(existingDefinition.getSource()) ||  // scanned same file twice
			newDefinition.equals(existingDefinition));  // scanned equivalent class twice


	/**
	 * 这方法里有三个判断: 只要有一个为true, 就会返回true, 外层就跳过, 不注册beanDefinition.
	 * (1)第一个判断: existingDefinition不是由注解生成的. 	(ScannedGenericBeanDefinition表示是由scan注解生成的definition)
	 * (2)第二个判断: 判断来源是否一致			(是否扫描一个文件扫描了多次,当多个扫描器扫描的路径冲突会出现这样的情况)
	 * (3)第三个判断: newDefinition必须==existingDefinition (扫描相同的class文件两次)
	 *
	 * 在我们用xml和注解定义两个bean时,
	 * 如果xml里面bean定义在前, existingDefinition就是xml定义的bean, 第一个返回的就是true, 外层会忽略后续的同名beanDefition
	 * 如果注解的bean在前已经被扫描注册,第一个判断返回false,第二个判断也是false, 第三个也是false,这时会再测注册,xml定义的beanDefition会覆盖注解定义的
	 * 如果出现class文件或者xml文件被扫描多次的情况都会返回true,忽略注册的.
	 */
}

6. 看到这里我们前面提出的问题已经解决了, 我们继续往下把spring的refresh方法看完.
这里要提到的是Spring中的BeanFactoryPostProcessor 和 BeanPostProcessor 这两个是Spring主要的扩展点,spring中很多功能都是围绕这两个类实现的,我们自己也可以实现这两个接口,对Spring容器做扩展. 这两个接口很重要.

refresh()方法里的invokeBeanFactoryPostProcessors(beanFactory)方法:


(1) BeanFactoryPostProcessor:

public interface BeanFactoryPostProcessor {

	/**
	 * Modify the application context's internal bean factory after its standard	//这个类用来修改bean factory的一些设置
	 * initialization. All bean definitions will have been loaded, but no beans		//所有的BeanFactoryPostProcessor执行时间点,都是在bean定义已经加载,但是还没要实例化之前.
	 * will have been instantiated yet. This allows for overriding or adding		//所以实现这个接口可以修改bean的全局配置
	 * properties even to eager-initializing beans.
	 * @param beanFactory the bean factory used by the application context
	 * @throws org.springframework.beans.BeansException in case of errors
	 */
	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

(2) BeanPostProcessor:

public interface BeanPostProcessor {	//实现了这个接口,在初始化bean前后会调用相应的方法;

	/**
	 * Apply this BeanPostProcessor to the given new bean instance <i>before</i> any bean
	 * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}			//postProcessBeforeInitialization在afterPropertiesSet之前生效
	 * or a custom init-method). The bean will already be populated with property values.
	 * The returned bean instance may be a wrapper around the original.				//可以返回原始bean的一个包装,通过动态代理就可以实现增强的功能
	 * @param bean the new bean instance
	 * @param beanName the name of the bean
	 * @return the bean instance to use, either the original or a wrapped one; if
	 * {@code null}, no subsequent BeanPostProcessors will be invoked
	 * @throws org.springframework.beans.BeansException in case of errors
	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
	 */
	Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;	//bean创建之前

	/**
	 * Apply this BeanPostProcessor to the given new bean instance <i>after</i> any bean
	 * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}			//执行时间再在afterPropertiesSet之后
	 * or a custom init-method). The bean will already be populated with property values.
	 * The returned bean instance may be a wrapper around the original.
	 * <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean
	 * instance and the objects created by the FactoryBean (as of Spring 2.0). The
	 * post-processor can decide whether to apply to either the FactoryBean or created
	 * objects or both through corresponding {@code bean instanceof FactoryBean} checks.
	 * <p>This callback will also be invoked after a short-circuiting triggered by a
	 * {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,
	 * in contrast to all other BeanPostProcessor callbacks.
	 * @param bean the new bean instance
	 * @param beanName the name of the bean
	 * @return the bean instance to use, either the original or a wrapped one; if
	 * {@code null}, no subsequent BeanPostProcessors will be invoked
	 * @throws org.springframework.beans.BeansException in case of errors
	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
	 * @see org.springframework.beans.factory.FactoryBean
	 */
	Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;	//bean创建之后
}

注意两者区别: 
1.BeanFactoryPostProcessor只有一个方法, BeanPostProcessor有两个方法
2.BeanFactoryPostProcessor的方法在生成bean实例之前, 是对beanFactory做一些修改和操作, 所以可以做一些bean的全局设置, 影响后面所有的bean创建.
  而BeanPostProcessor只是在具体的bean创建之前或者之后修改bean的配置或者对bean做增强,aop功能就是这么实现的.

7. 回到refresh()方法里的invokeBeanFactoryPostProcessors(beanFactory)方法:
invokeBeanFactoryPostProcessors(beanFactory)方法会找出所有的实现了BeanFactoryPostProcessor接口的方法 (里面有些特殊的BeanFactoryPostProcessor需要优先执行),
并且会执行这些所有的方法,可以对beanFactory做一些全局的修改. mybatis和spring的集成就是在这里实现的, 继续往下看.

/**
 * Instantiate and invoke all registered BeanFactoryPostProcessor beans,	// 实例化并且调用所有实现了BeanFactoryPostProcessor的类方法
 * respecting explicit order if given.
 * <p>Must be called before singleton instantiation.						// 必须在单例bean实例化之前调用
 */
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	// Invoke BeanDefinitionRegistryPostProcessors first, if any.
	Set<String> processedBeans = new HashSet<String>();
	if (beanFactory instanceof BeanDefinitionRegistry) {
		BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
		List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>();	//正常的BeanFactoryPostProcessor
		List<BeanDefinitionRegistryPostProcessor> registryPostProcessors =
				new LinkedList<BeanDefinitionRegistryPostProcessor>();    //BeanDefinitionRegistryPostProcessor
		for (BeanFactoryPostProcessor postProcessor : getBeanFactoryPostProcessors()) {		//遍历所有的实现了BeanFactoryPostProcessor接口的类
			if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {				//优先处理BeanDefinitionRegistryPostProcessor, 比如mybatis scaner就是实现这个特殊接口做到先实例化mapper的bean的
				BeanDefinitionRegistryPostProcessor registryPostProcessor =
						(BeanDefinitionRegistryPostProcessor) postProcessor;
				registryPostProcessor.postProcessBeanDefinitionRegistry(registry);
				registryPostProcessors.add(registryPostProcessor);
			}
			else {
				regularPostProcessors.add(postProcessor);
			}
		}
	后面代码省略... ...

 




  • 6
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值