Spring源码分析 为什么xml定义的bean优先于注解定义的bean ?
2016-08-21 17:51
791 查看
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 {
2. refresh()方法里的obtainFreshBeanFactory()方法
3. obtainFreshBeanFactory方法里第一行的refreshBeanFactory()方法:
我们在xml里面用<bean .../>标签定义的正常的beanDefinition都是在这里解析加载的;
有一类特殊的标签, 例如<context: .../> 这是在spring自定义的标签,用于做特殊处理的
解析这种标签需要spring.handlers配置文件的帮助, spring.handlers里面定义了各种自定义标签和对应的处理器.
spring-context模块的spring.handlers如下:
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 (详细见下面代码)
4. 方法checkCandidate会处理冲突, 关键就在其中的isCompatible(beanDefinition, existingDef)方法
5. isCompatible(beanDefinition, existingDef)方法;
6. 看到这里我们前面提出的问题已经解决了, 我们继续往下把spring的refresh方法看完.
这里要提到的是Spring中的BeanFactoryPostProcessor 和 BeanPostProcessor 这两个是Spring主要的扩展点,spring中很多功能都是围绕这两个类实现的,我们自己也可以实现这两个接口,对Spring容器做扩展. 这两个接口很重要.
refresh()方法里的invokeBeanFactoryPostProcessors(beanFactory)方法:
注意两者区别:
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的集成就是在这里实现的, 继续往下看.
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); } } 后面代码省略... ...
相关文章推荐
- Spring对注解(Annotation)处理源码分析1——扫描和读取Bean定义
- Spring对注解(Annotation)处理源码分析1——扫描和读取Bean定义
- Spring对注解(Annotation)处理源码分析1——扫描和读取Bean定义
- Spring对注解(Annotation)处理源码分析1——扫描和读取Bean定义
- Spring对注解(Annotation)处理源码分析1——扫描和读取Bean定义
- Spring对注解(Annotation)处理源码分析1——扫描和读取Bean定义
- spring 注解源码分析-扫描和读取bean定义
- Spring对注解(Annotation)处理源码分析1——扫描和读取Bean定义
- Spring对注解(Annotation)处理源码分析1——扫描和读取Bean定义
- (转)Spring对注解(Annotation)处理源码分析1——扫描和读取Bean定义
- [Java]从spring(spring boot)的启动分析注解定义方式的bean的加载
- Spring源码分析之XmlbeanFactory继承关系图
- Spring3.2 中 Bean 定义之基于 XML 配置方式的源码解析
- Spring3.2 中 Bean 定义之基于 XML 配置方式的源码解析
- Spring bean定义解析源码分析
- spring源码分析(2)——Bean 定义的解析与Bean的注册
- Spring3.2 中 Bean 定义之基于 XML 配置方式的源码解析
- Spring源码分析1--IoC容器载入Bean定义资源
- Spring3.2 中 Bean 定义之基于 XML 配置方式的源码解析
- spring源码分析(web)--通过注解获取bean源码分析