您的位置:首页 > 编程语言 > Java开发

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

2016-08-21 17:51 831 查看
    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.
4000
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);
}
}
后面代码省略... ...

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息