Spring源碼分析(四)之@Configuration @Bean的方式配置bean

原文地址:http://blog.csdn.net/jin5203344/article/details/78590111

             在微服務大趨勢下Springboot,Springcloud成爲更多公司新項目技術框架的選型 ,Springboot簡潔的基本零配置,很重要的一點是將以前通過xml方式配置bean轉換爲

通過@Configuration @Bean的方式來進行,今天主要分析下Spring是如何來實現對這兩個註解進行處理的


             通過Springboot的啓動來跟蹤分析容器的啓動(這裏只是簡單的帶過,後面會在springboot源碼分析中,詳細講解),run方法具體實現如下:


[java]  view plain  copy
  1. public ConfigurableApplicationContext run(String... args) {  
  2.         if (this.running.get()) {  
  3.             // If already created we just return the existing context  
  4.             return this.context;  
  5.         }  
  6.         configureAsChildIfNecessary(args);  
  7.         if (this.running.compareAndSet(falsetrue)) {  
  8.             synchronized (this.running) {  
  9.                 // 如果容器未啓動,啓動容器,裝配資源  
  10.                 this.context = build().run(args);  
  11.             }  
  12.         }  
  13.         return this.context;  
  14.     }  

[java]  view plain  copy
  1. public ConfigurableApplicationContext run(String... args) {  
  2.         StopWatch stopWatch = new StopWatch();  
  3.         stopWatch.start();  
  4.         ConfigurableApplicationContext context = null;  
  5.         FailureAnalyzers analyzers = null;  
  6.         configureHeadlessProperty();  
  7.         SpringApplicationRunListeners listeners = getRunListeners(args);  
  8.         listeners.starting();  
  9.         try {  
  10.             ApplicationArguments applicationArguments = new DefaultApplicationArguments(  
  11.                     args);  
  12.             ConfigurableEnvironment environment = prepareEnvironment(listeners,  
  13.                     applicationArguments);  
  14.             Banner printedBanner = printBanner(environment);//打印beanner  
  15.             context = createApplicationContext();//創建默認的上下文  
  16.             analyzers = new FailureAnalyzers(context);  
  17.             prepareContext(context, environment, listeners, applicationArguments,  
  18.                     printedBanner);  
  19.             refreshContext(context);// 刷新容器  
  20.             afterRefresh(context, applicationArguments);  
  21.             listeners.finished(context, null);  
  22.             stopWatch.stop();  
  23.             if (this.logStartupInfo) {  
  24.                 new StartupInfoLogger(this.mainApplicationClass)  
  25.                         .logStarted(getApplicationLog(), stopWatch);  
  26.             }  
  27.             return context;  
  28.         }  
  29.         catch (Throwable ex) {  
  30.             handleRunFailure(context, listeners, analyzers, ex);  
  31.             throw new IllegalStateException(ex);  
  32.         }  
  33.     }  

重點關注refreshContext,在refreshContext中 就有第一篇中分析容器入口的refresh方法

[java]  view plain  copy
  1. private void refreshContext(ConfigurableApplicationContext context) {  
  2.         refresh(context);  
  3.         if (this.registerShutdownHook) {  
  4.             try {  
  5.                 context.registerShutdownHook();  
  6.             }  
  7.             catch (AccessControlException ex) {  
  8.                 // Not allowed in some environments.  
  9.             }  
  10.         }  
  11.     }  

事實上 我們分析的入口依然是refresh這個核心方法,這裏就不重複貼源碼了,這是我們之前loadBeanDefinitions換成 AnnotationConfigWebApplicationContext 類


AnnotationBeanDefinitionReader 對應構造函數 爲:

[java]  view plain  copy
  1. public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {  
  2.         Assert.notNull(registry, "BeanDefinitionRegistry must not be null");  
  3.         Assert.notNull(environment, "Environment must not be null");  
  4.         this.registry = registry;  
  5.         this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);  
  6.         AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);  
  7.     }  

可以看到 最後一行 註冊AnnotationConfigProcessors,有什麼用呢,接着看其實現:

[java]  view plain  copy
  1. public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(  
  2.             BeanDefinitionRegistry registry, Object source) {  
  3.   
  4.         DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);  
  5.         if (beanFactory != null) {  
  6.             if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {  
  7.                 beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);  
  8.             }  
  9.             if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {  
  10.                 beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());  
  11.             }  
  12.         }  
  13.   
  14.         Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);  
  15.                 // 處理Configuration註解的 postProcessor  
  16.         if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {  
  17.             RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);  
  18.             def.setSource(source);  
  19.             beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));  
  20.         }  
  21.                 // 處理autowired註解的  postProcessor  
  22.         if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {  
  23.             RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);  
  24.             def.setSource(source);  
  25.             beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));  
  26.         }  
  27.                 // 處理required註解的 postProcessor  
  28.         if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {  
  29.             RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);  
  30.             def.setSource(source);  
  31.             beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));  
  32.         }  
  33.   
  34.         // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.  
  35.         if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {  
  36.             RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);  
  37.             def.setSource(source);  
  38.             beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));  
  39.         }  
  40.   
  41.         // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.  
  42.         if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {  
  43.             RootBeanDefinition def = new RootBeanDefinition();  
  44.             try {  
  45.                 def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,  
  46.                         AnnotationConfigUtils.class.getClassLoader()));  
  47.             }  
  48.             catch (ClassNotFoundException ex) {  
  49.                 throw new IllegalStateException(  
  50.                         "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);  
  51.             }  
  52.             def.setSource(source);  
  53.             beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));  
  54.         }  
  55.   
  56.         if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {  
  57.             RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);  
  58.             def.setSource(source);  
  59.             beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));  
  60.         }  
  61.         if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {  
  62.             RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);  
  63.             def.setSource(source);  
  64.             beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));  
  65.         }  
  66.   
  67.         return beanDefs;  
  68.     }  

這裏我們只用關係,configuration註解的處理,實際是向容器中接入了 對Configuration註解的 處理類 ConfigurationClassPostProcessor,

那我們有個疑問,這個類什麼時候會調用呢?  回到refresh方法中,有一行關鍵代碼

// Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory);
方法內容比較多,這裏就選取一個分支來說明下

String[] postProcessorNames =
      beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);

// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered. List<BeanDefinitionRegistryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();
for (String ppName : postProcessorNames) {
   if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
      priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
      processedBeans.add(ppName);
   }
}
sortPostProcessors(beanFactory, priorityOrderedPostProcessors);
registryPostProcessors.addAll(priorityOrderedPostProcessors);
invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);
第一行:從工廠類中得到所有 BeanDefinitionRegistryPostProcessor類型的bean

第三——九行 循環判斷添加到 需要處理的列表中

第十二行:執行具體需要處理的postProcessors

具體實現如下:

private static void invokeBeanDefinitionRegistryPostProcessors(
      Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {

   for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
      postProcessor.postProcessBeanDefinitionRegistry(registry);
   }
}
也就是循環調用postProcessor的 postProcessBeanDefinitionRegistry方法,而ConfigurationClassPostProcessor類的對應方法內部調用邏輯順序

postProcessBeanDefinitionRegistry  ——》 processConfigBeanDefinitions ——》

[java]  view plain  copy
  1. // Parse each @Configuration class  
  2. ConfigurationClassParser parser = new ConfigurationClassParser(  
  3.       this.metadataReaderFactory, this.problemReporter, this.environment,  
  4.       this.resourceLoader, this.componentScanBeanNameGenerator, registry);  
  5.   
  6. Set<BeanDefinitionHolder> candidates = new LinkedHashSet<BeanDefinitionHolder>(configCandidates);  
  7. Set<ConfigurationClass> alreadyParsed = new HashSet<ConfigurationClass>(configCandidates.size());  
  8. do {  
  9.    parser.parse(candidates);  
  10.    parser.validate();  
  11.    ....  
  12. }while (!candidates.isEmpty());  
從源碼註釋就能看出  是解析 @Configuration 註解的類  通過ConfigurationClassParser 來進行處理

parser ——》processConfigurationClass ——》doProcessConfigurationClass

[java]  view plain  copy
  1. protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {  
  2.         // 遞歸處理成員類  
  3.         processMemberClasses(configClass, sourceClass);  
  4.   
  5.         // 處理 @PropertySource 註解  
  6.         for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(  
  7.                 sourceClass.getMetadata(), PropertySources.class, org.springframework.context.annotation.PropertySource.class)) {  
  8.             if (this.environment instanceof ConfigurableEnvironment) {  
  9.                 processPropertySource(propertySource);  
  10.             }  
  11.             else {  
  12.                 logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +  
  13.                         "]. Reason: Environment must implement ConfigurableEnvironment");  
  14.             }  
  15.         }  
  16.   
  17.         // 處理 @ComponentScan 註解  
  18.         AnnotationAttributes componentScan = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ComponentScan.class);  
  19.         if (componentScan != null && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {  
  20.             // The config class is annotated with @ComponentScan -> perform the scan immediately  
  21.             Set<BeanDefinitionHolder> scannedBeanDefinitions =  
  22.                     this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());  
  23.             // Check the set of scanned definitions for any further config classes and parse recursively if necessary  
  24.             for (BeanDefinitionHolder holder : scannedBeanDefinitions) {  
  25.                 if (ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(), this.metadataReaderFactory)) {  
  26.                     parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());  
  27.                 }  
  28.             }  
  29.         }  
  30.   
  31.         // 處理 @Import 註解  
  32.         processImports(configClass, sourceClass, getImports(sourceClass), true);  
  33.   
  34.         // 處理 @ImportResource 註解  
  35.         if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) {  
  36.             AnnotationAttributes importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);  
  37.             String[] resources = importResource.getAliasedStringArray("locations", ImportResource.class, sourceClass);  
  38.             Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");  
  39.             for (String resource : resources) {  
  40.                 String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);  
  41.                 configClass.addImportedResource(resolvedResource, readerClass);  
  42.             }  
  43.         }  
  44.   
  45.         // 處理 @Bean 註解  
  46.         Set<MethodMetadata> beanMethods = sourceClass.getMetadata().getAnnotatedMethods(Bean.class.getName());  
  47.         for (MethodMetadata methodMetadata : beanMethods) {  
  48.             configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));  
  49.         }  
  50.   
  51.         // 處理接口中默認方法  
  52.         for (SourceClass ifc : sourceClass.getInterfaces()) {  
  53.             beanMethods = ifc.getMetadata().getAnnotatedMethods(Bean.class.getName());  
  54.             for (MethodMetadata methodMetadata : beanMethods) {  
  55.                 if (!methodMetadata.isAbstract()) {  
  56.                     // A default method or other concrete method on a Java 8+ interface...  
  57.                     configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));  
  58.                 }  
  59.             }  
  60.         }  
  61.   
  62.         // 處理父類  
  63.         if (sourceClass.getMetadata().hasSuperClass()) {  
  64.             String superclass = sourceClass.getMetadata().getSuperClassName();  
  65.             if (!superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) {  
  66.                 this.knownSuperclasses.put(superclass, configClass);  
  67.                 // Superclass found, return its annotation metadata and recurse  
  68.                 return sourceClass.getSuperClass();  
  69.             }  
  70.         }  
  71.   
  72.         // No superclass -> processing is complete  
  73.         return null;  
  74.     }  

其他註解的處理這裏暫且不作分析,後面有機會再補上,有興趣的讀者可以自行查看源碼學習,原理都差不多,解析到對於的信息添加到configClass中

可以看到通過解析@Bean註解,獲取到所有帶有@Bean註解的方法,創建對應的BeanMethod添加到configClass中,回到processConfigBeanDefinitions方法

this.reader.loadBeanDefinitions(configClasses);
通過configClasses加載bean定義

查看具體實現

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
   TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
   for (ConfigurationClass configClass : configurationModel) {
      loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
   }
}
循環加載

private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass,
      TrackedConditionEvaluator trackedConditionEvaluator) {

   if (trackedConditionEvaluator.shouldSkip(configClass)) {
      String beanName = configClass.getBeanName();
      if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
         this.registry.removeBeanDefinition(beanName);
      }
      this.importRegistry.removeImportingClassFor(configClass.getMetadata().getClassName());
      return;
   }

   if (configClass.isImported()) {
      registerBeanDefinitionForImportedConfigurationClass(configClass);
   }
   // 循環加載 beanMethod
  for (BeanMethod beanMethod : configClass.getBeanMethods()) {
      loadBeanDefinitionsForBeanMethod(beanMethod);
   }
   loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
   loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

loadBeanDefinitionsForBeanMethod  字面意思  爲beanMethod加載beanDefinition

private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
   ConfigurationClass configClass = beanMethod.getConfigurationClass();
   MethodMetadata metadata = beanMethod.getMetadata();
   String methodName = metadata.getMethodName();

   // Do we need to mark the bean as skipped by its condition?  if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
      configClass.skippedBeanMethods.add(methodName);
      return;
   }
   if (configClass.skippedBeanMethods.contains(methodName)) {
      return;
   }

   // Consider name and any aliases  AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
   List<String> names = new ArrayList<String>(Arrays.asList(bean.getStringArray("name")));
   String beanName = (names.size() > 0 ? names.remove(0) : methodName);

   // Register aliases even when overridden  for (String alias : names) {
      this.registry.registerAlias(beanName, alias);
   }

   // Has this effectively been overridden before (e.g. via XML)?  if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
      return;
   }

   ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
   beanDef.setResource(configClass.getResource());
   beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));

   if (metadata.isStatic()) {
      // static @Bean method  beanDef.setBeanClassName(configClass.getMetadata().getClassName());
      beanDef.setFactoryMethodName(methodName);
   }
   else {
      // instance @Bean method  beanDef.setFactoryBeanName(configClass.getBeanName());
      beanDef.setUniqueFactoryMethodName(methodName);
   }
   beanDef.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
   beanDef.setAttribute(RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);

   AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);

   Autowire autowire = bean.getEnum("autowire");
   if (autowire.isAutowire()) {
      beanDef.setAutowireMode(autowire.value());
   }

   String initMethodName = bean.getString("initMethod");
   if (StringUtils.hasText(initMethodName)) {
      beanDef.setInitMethodName(initMethodName);
   }

   String destroyMethodName = bean.getString("destroyMethod");
   if (destroyMethodName != null) {
      beanDef.setDestroyMethodName(destroyMethodName);
   }

   // Consider scoping  ScopedProxyMode proxyMode = ScopedProxyMode.NO;
   AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
   if (attributes != null) {
      beanDef.setScope(attributes.getAliasedString("value", Scope.class, configClass.getResource()));
      proxyMode = attributes.getEnum("proxyMode");
      if (proxyMode == ScopedProxyMode.DEFAULT) {
         proxyMode = ScopedProxyMode.NO;
      }
   }

   // Replace the original bean definition with the target one, if necessary  BeanDefinition beanDefToRegister = beanDef;
   if (proxyMode != ScopedProxyMode.NO) {
      BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
            new BeanDefinitionHolder(beanDef, beanName), this.registry, proxyMode == ScopedProxyMode.TARGET_CLASS);
      beanDefToRegister = new ConfigurationClassBeanDefinition(
            (RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata);
   }

   if (logger.isDebugEnabled()) {
      logger.debug(String.format("Registering bean definition for @Bean method %s.%s()",
            configClass.getMetadata().getClassName(), beanName));
   }

   this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}

通過元數據以及相關信息 裝配 註冊beanDefinition