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里面用标签定义的正常的beanDefinition都是在这里解析加载的;
有一类特殊的标签, 例如 这是在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.
 * 

This method does not 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 doScan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); Set beanDefinitions = new LinkedHashSet(); for (String basePackage : basePackages) { Set 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.
 * 

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 before 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 after 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.
	 * 

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. *

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.
 * 

Must be called before singleton instantiation. // 必须在单例bean实例化之前调用 */ protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { // Invoke BeanDefinitionRegistryPostProcessors first, if any. Set processedBeans = new HashSet(); if (beanFactory instanceof BeanDefinitionRegistry) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; List regularPostProcessors = new LinkedList(); //正常的BeanFactoryPostProcessor List registryPostProcessors = new LinkedList(); //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); } } 后面代码省略... ...


 




你可能感兴趣的:(spring)