spring注解配置原理浅析

除了使用xml文件配置以外,spring还支持使用注解实现JavaBean的配置,其具体实现方式网上已经介绍的很详细,这里就不再赘述了。本文将主要通过源代码解析spring注解配置JavaBean的全过程。这里主要分析的是@component和@Autowired这两个注解。

    首先要明确这样一个问题,注解配置和xml文件配置二者并“完全”不冲突。说不完全是因为如果使用@component修饰一个类,那么就无法通过xml为这个类设置某些参数,如property的值。但是通过xml文件配置的JavaBean则可以使用@Autowired完成属性的配置。这个问题说明了注解配置方法是xml文件配置方法的进化版,并且是依附于xml文件配置的。下面将主要介绍其实现原理。

    使用注解配置方法的xml文件配置:

[html]  view plain  copy
  1. <context:component-scan base-package="com.luanbin.annotation" />  
    根据上一篇博客的介绍,可以找到这个component-scan对应的解析类AnnotationConfigBeanDefinitionParser       

    该解析类的parse方法:

[java]  view plain  copy
  1. public BeanDefinition parse(Element element, ParserContext parserContext) {  
  2.         Object source = parserContext.extractSource(element);  
  3.   
  4.         // Obtain bean definitions for all relevant BeanPostProcessors.  
  5.         Set processorDefinitions =  
  6.                 AnnotationConfigUtils.registerAnnotationConfigProcessors(parserContext.getRegistry(), source);  
  7.   
  8.         // Register component for the surrounding  element.  
  9.         CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);  
  10.         parserContext.pushContainingComponent(compDefinition);  
  11.   
  12.         // Nest the concrete beans in the surrounding component.  
  13.         for (BeanDefinitionHolder processorDefinition : processorDefinitions) {  
  14.             parserContext.registerComponent(new BeanComponentDefinition(processorDefinition));  
  15.         }  
  16.   
  17.         // Finally register the composite component.  
  18.         parserContext.popAndRegisterContainingComponent();  
  19.   
  20.         return null;  
  21.     }  

    parse方法只完成了一项工作,扫描指定的package,同时将被@component修饰的类包装成beandefinition,需要尤其注意的事,因为注解相比于xml文件拥有的信息较少,因此该beandefinition除了实现类,即被@component修饰的类信息以外,不包含其他信息,如构造函数,各个property的属性等。JavaBean在AbstractAutowireCapableBeanFactory的doCreatBean函数中被实例化并且配置相关属性,其具体代码如下:

[java]  view plain  copy
  1. protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {  
  2.         // Instantiate the bean.  
  3.         BeanWrapper instanceWrapper = null;  
  4.         if (mbd.isSingleton()) {  
  5.             instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);  
  6.         }  
  7.         if (instanceWrapper == null) {  
  8.             instanceWrapper = createBeanInstance(beanName, mbd, args);  
  9.         }  
  10.         final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);  
  11.         Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);  
  12.   
  13.         // Allow post-processors to modify the merged bean definition.  
  14.         synchronized (mbd.postProcessingLock) {  
  15.             if (!mbd.postProcessed) {  
  16.                 applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);  
  17.                 mbd.postProcessed = true;  
  18.             }  
  19.         }  
  20.   
  21.         // Eagerly cache singletons to be able to resolve circular references  
  22.         // even when triggered by lifecycle interfaces like BeanFactoryAware.  
  23.         boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&  
  24.                 isSingletonCurrentlyInCreation(beanName));  
  25.         if (earlySingletonExposure) {  
  26.             if (logger.isDebugEnabled()) {  
  27.                 logger.debug("Eagerly caching bean '" + beanName +  
  28.                         "' to allow for resolving potential circular references");  
  29.             }  
  30.             addSingletonFactory(beanName, new ObjectFactory() {  
  31.                 public Object getObject() throws BeansException {  
  32.                     return getEarlyBeanReference(beanName, mbd, bean);  
  33.                 }  
  34.             });  
  35.         }  
  36.   
  37.         // Initialize the bean instance.  
  38.         Object exposedObject = bean;  
  39.         try {  
  40.             populateBean(beanName, mbd, instanceWrapper);  
  41.             if (exposedObject != null) {  
  42.                 exposedObject = initializeBean(beanName, exposedObject, mbd);  
  43.             }  
  44.         }  
  45.         catch (Throwable ex) {  
  46.             if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {  
  47.                 throw (BeanCreationException) ex;  
  48.             }  
  49.             else {  
  50.                 throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);  
  51.             }  
  52.         }  
  53.   
  54.         if (earlySingletonExposure) {  
  55.             Object earlySingletonReference = getSingleton(beanName, false);  
  56.             if (earlySingletonReference != null) {  
  57.                 if (exposedObject == bean) {  
  58.                     exposedObject = earlySingletonReference;  
  59.                 }  
  60.                 else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {  
  61.                     String[] dependentBeans = getDependentBeans(beanName);  
  62.                     Set actualDependentBeans = new LinkedHashSet(dependentBeans.length);  
  63.                     for (String dependentBean : dependentBeans) {  
  64.                         if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {  
  65.                             actualDependentBeans.add(dependentBean);  
  66.                         }  
  67.                     }  
  68.                     if (!actualDependentBeans.isEmpty()) {  
  69.                         throw new BeanCurrentlyInCreationException(beanName,  
  70.                                 "Bean with name '" + beanName + "' has been injected into other beans [" +  
  71.                                 StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +  
  72.                                 "] in its raw version as part of a circular reference, but has eventually been " +  
  73.                                 "wrapped. This means that said other beans do not use the final version of the " +  
  74.                                 "bean. This is often the result of over-eager type matching - consider using " +  
  75.                                 "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");  
  76.                     }  
  77.                 }  
  78.             }  
  79.         }  
  80.   
  81.         // Register bean as disposable.  
  82.         try {  
  83.             registerDisposableBeanIfNecessary(beanName, bean, mbd);  
  84.         }  
  85.         catch (BeanDefinitionValidationException ex) {  
  86.             throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);  
  87.         }  
  88.   
  89.         return exposedObject;  
  90.     }  
    其中createBeanInstance(beanName, mbd, args)的功能是根据beandefinition反射出来累的构造函数,并通过构造函数完成JavaBean的实例化,其具体代码如下:
[java]  view plain  copy
  1. protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {  
  2.         // Make sure bean class is actually resolved at this point.  
  3.         Class beanClass = resolveBeanClass(mbd, beanName);  
  4.   
  5.         if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {  
  6.             throw new BeanCreationException(mbd.getResourceDescription(), beanName,  
  7.                     "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());  
  8.         }  
  9.   
  10.         if (mbd.getFactoryMethodName() != null)  {  
  11.             return instantiateUsingFactoryMethod(beanName, mbd, args);  
  12.         }  
  13.   
  14.         // Shortcut when re-creating the same bean...  
  15.         boolean resolved = false;  
  16.         boolean autowireNecessary = false;  
  17.         if (args == null) {  
  18.             synchronized (mbd.constructorArgumentLock) {  
  19.                 if (mbd.resolvedConstructorOrFactoryMethod != null) {  
  20.                     resolved = true;  
  21.                     autowireNecessary = mbd.constructorArgumentsResolved;  
  22.                 }  
  23.             }  
  24.         }  
  25.         if (resolved) {  
  26.             if (autowireNecessary) {  
  27.                 return autowireConstructor(beanName, mbd, nullnull);  
  28.             }  
  29.             else {  
  30.                 return instantiateBean(beanName, mbd);  
  31.             }  
  32.         }  
  33.   
  34.         // Need to determine the constructor...  
  35.         Constructor[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);  
  36.         if (ctors != null ||  
  37.                 mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||  
  38.                 mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {  
  39.             return autowireConstructor(beanName, mbd, ctors, args);  
  40.         }  
  41.   
  42.         // No special handling: simply use no-arg constructor.  
  43.         return instantiateBean(beanName, mbd);  
  44.     }  
    在完成JavaBean的实例化之后,spring通过BeanPostProcessor对该JavaBean进行处理。
[java]  view plain  copy
  1. applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);  

    其中AutowiredAnnotationBeanPostProcessor的主要工作就是判断JavaBean中是否有被@Autowired修饰的field和method,并将该信息包装成InjecMetadata保存在list中。其核心代码如下:

[java]  view plain  copy
  1. private InjectionMetadata findAutowiringMetadata(Class clazz) {  
  2.         // Quick check on the concurrent map first, with minimal locking.  
  3.         InjectionMetadata metadata = this.injectionMetadataCache.get(clazz);  
  4.         if (metadata == null) {  
  5.             synchronized (this.injectionMetadataCache) {  
  6.                 metadata = this.injectionMetadataCache.get(clazz);  
  7.                 if (metadata == null) {  
  8.                     metadata = buildAutowiringMetadata(clazz);  
  9.                     this.injectionMetadataCache.put(clazz, metadata);  
  10.                 }  
  11.             }  
  12.         }  
  13.         return metadata;  
  14.     }  
    和xml配置的JavaBean一样,spring通过populateBean方法完成JavaBean中被@Autowired所修饰的属性的注入。而注入的过程依旧是调用 BeanPostProcessor的相关方法。注入的方法如下:

[java]  view plain  copy
  1. public PropertyValues postProcessPropertyValues(  
  2.             PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {  
  3.   
  4.         InjectionMetadata metadata = findAutowiringMetadata(bean.getClass());  
  5.         try {  
  6.             metadata.inject(bean, beanName, pvs);  
  7.         }  
  8.         catch (Throwable ex) {  
  9.             throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);  
  10.         }  
  11.         return pvs;  
  12.     }  
   而metadata的注入过程实际上就是从beanfactory中获取JavaBean的实例并配置到目标bean上。可以看得出来,这种实例化方法存在递归过程。因此在实例化之前,spring会检测是否存在循环依赖,检测循环依赖的方法将在之后进行介绍。

0

你可能感兴趣的:(java后端框架等技术,spring,javabean)