本篇文章是對上一篇文章Spring刷新應用上下文的補充說明,詳細講述了上一篇文章中的第五步(實例化並調用全部註冊的beanFactory後置處理器)中Spring解析@Configuration註解的過程。java
在Spring3.0以前的Spring核心框架中,咱們啓動一個Spring容器必須使用一個XML文件。而到了3.0以後的版本Spring爲建立容器新增了一個入口類——AnnotationConfigApplicationContext。AnnotationConfigApplicationContext和過去的ClassPathXmlApplicationContext、FileSystemXmlApplicationContext等方法不一樣的是他不用再指定任何XML配置文件,而是能夠經過指定類向容器添加Bean。web
所以,從Spring3.0後,只要在配置類上加@Configuration註解就能夠替換以前的xml配置文件,被註解的類內部包含有一個或多個被@Bean註解的方法,這些方法將會被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext類進行掃描,並用於構建bean定義,初始化Spring容器。從使用的角度來講能夠把他理解爲XML配置中的<beans>標籤,可是兩者又有些細節的差別。在<beans>標籤中除了使用<bean>聲名Bean之外,還有各類<context>標籤來擴展功能,好比<context:component-scan/>、<context:annotation-config />以及<import>等,這些擴展的功能並非@Configuration註解的參數,而是經過其它註解來實現的如:@ComponentScan、@Import。spring
使用@Configuration註解需知足如下要求express
Spring對@Configuration註解類的解析最終是在ConfigurationClassPostProcessor類調用的processConfigBeanDefinitions方法中使用Spring的工具類ConfigurationClassParser來進行的。ConfigurationClassPostProcessor類是BeanFactoryPostProcessor的實現(看下圖),BeanFactoryPostProcessor用於spring應用啓動過程當中@Configuration類的處理(發現和處理全部的配置類,註冊其中的bean定義)。segmentfault
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Configuration { @AliasFor(annotation = Component.class) String value() default ""; //能夠自定義Bean的名稱 }
介紹
ConfigurationClassPostProcessor 位於 org.springframework.context.annotation 包中,這是一個 BeanDefinitionRegistryPostProcessor,隱含地也實現了接口BeanFactoryPostProcessor,用於spring 應用啓動過程當中 @Configuration 類的處理(發現和處理全部的配置類,註冊其中的bean定義)。緩存
引入時機app
調用時機
ConfigurationClassPostProcessor既實現了BeanDefinitionRegistryPostProcessor定義的方法postProcessBeanDefinitionRegistry,也實現了接口BeanFactoryPostProcessor定義的方法postProcessBeanFactory。框架
AbstractApplicationContext.refresh()方法執行時,在BeanFactory,也就是Spring容器被準備(prepare)和postProcess以後,AbstractApplicationContext的invokeBeanFactoryPostProcessors()方法被調用,這個方法用來執行全部容器中被做爲bean註冊的BeanFactoryPostProcessor,其中就包括對ConfigurationClassPostProcessor方法postProcessBeanDefinitionRegistry()以及postProcessBeanFactory()方法的調用。ide
調用過程
解析過程是在容器刷新方法中--refreshContext(context) --> refresh(context) --> ApplicationContext.refresh()
--> invokeBeanFactoryPostProcessor(beanFactory)(該方法在容器刷新專欄有詳細講解,就是調用了PostProcessorRegistrationDelegate類的invokeBeanFactoryPostProcessors方法)這個方法調用全部的BeanFactoryPostProcessor,同時也就啓動了Configuration類的解析。此時的BeanFactory中已經加載了main class,以及內部定義的class。內部定義的class都是帶internal的,這些並非Configuration Class,解析程序會忽略這些類,最後只有SpringBoot的啓動類(如:DemoApplication)會進行Configuration的解析處理。函數
這裏之全部這樣作的緣由是上述方法執行時有可能註冊新的BeanDefinitionRegistryPostProcessor/BeanFactoryPostProcessor到容器,而這些新註冊的BeanDefinitionRegistryPostProcessor/BeanFactoryPostProcessor也須要在這個階段執行。
注意事項
由於配置類中定義的每一個bean定義方法都必需要趕在其它BeanFactoryPostProcessor應用前,因此完成bean定義註冊任務的ConfigurationClassPostProcessor 被設計爲擁有最高執行優先級Ordered.HIGHEST_PRECEDENCE。
重提上一篇文章Spring 刷新應用上下文中的invokeBeanFactoryPostProcessors方法,用以引出下文。
//實例化並調用全部註冊的beanFactory後置處理器 public static void invokeBeanFactoryPostProcessors( ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) { Set<String> processedBeans = new HashSet<>(); if (beanFactory instanceof BeanDefinitionRegistry) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<>(); List<BeanDefinitionRegistryPostProcessor> registryProcessors = new LinkedList<>(); //遍歷全部的beanFactoryPostProcessors, //將BeanDefinitionRegistryPostProcessor和普通BeanFactoryPostProcessor區分開 for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) { if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) { BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor; //主要看這裏!!! registryProcessor.postProcessBeanDefinitionRegistry(registry); registryProcessors.add(registryProcessor); } else { regularPostProcessors.add(postProcessor); } } ....省略此處代碼在以前的文章已經介紹過了
該方法主要作了如下事情:
registryProcessor.postProcessBeanDefinitionRegistry(registry)這一步(調用了ConfigurationClassPostProcessor類的postProcessBeanDefinitionRegistry方法)使用工具ConfigurationClassParser嘗試發現全部的配置(@Configuration)類,使用工具ConfigurationClassBeanDefinitionReader註冊所發現的配置類中全部的bean定義。結束執行的條件是全部配置類都被發現和處理,相應的bean定義註冊到容器。
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
下面看ConfigurationClassPostProcessor類中postProcessBeanDefinitionRegistry()的處理邏輯,該方法使用工具ConfigurationClassParser嘗試發現全部的配置(@Configuration)類,使用工具ConfigurationClassBeanDefinitionReader註冊所發現的配置類中全部的bean定義。結束執行的條件是全部配置類都被發現和處理,相應的bean定義註冊到容器。
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { //根據BeanDefinitionRegistry,生成registryId 是全局惟一的。 int registryId = System.identityHashCode(registry); // 判斷,若是這個registryId 已經被執行過了,就不可以再執行了,不然拋出異常 if (this.registriesPostProcessed.contains(registryId)) { throw new IllegalStateException( "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry); } if (this.factoriesPostProcessed.contains(registryId)) { throw new IllegalStateException( "postProcessBeanFactory already called on this post-processor against " + registry); } // 已經執行過的registry防止重複執行 this.registriesPostProcessed.add(registryId); // 調用processConfigBeanDefinitions 進行Bean定義的加載 processConfigBeanDefinitions(registry); }
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { // 記錄候選配置類 List<BeanDefinitionHolder> configCandidates = new ArrayList<>(); // 獲取已經註冊的bean名稱(將容器中已經登記的Bean定義做爲候選配置類名稱) String[] candidateNames = registry.getBeanDefinitionNames(); // 程序此時處於容器啓動的早期,一般此時 candidateNames 中實際上只會有一個配置類(即...Application啓動類) for (String beanName : candidateNames) { BeanDefinition beanDef = registry.getBeanDefinition(beanName); //若是beanDef如今就已經肯定了是full或者lite,說明已經被解析過了,因此再來就直接輸出debug if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) || ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) { if (logger.isDebugEnabled()) { logger.debug("Bean definition has already been processed as a configuration class: " + beanDef); } } // 檢查是不是@Configuration的Class,若是是就標記下屬性:full 或者lite。 else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) { //若是當前的bean是Javabean配置類(含有@Configuration註解的類),則加入到集合configCandidates中 configCandidates.add(new BeanDefinitionHolder(beanDef, beanName)); } } // 若是一個配置文件類都沒找到,直接返回 if (configCandidates.isEmpty()) { return; } // 把這些配置按照@Order註解進行排序(@Configuration註解的配置文件是支持order排序的。可是普通bean不行) configCandidates.sort((bd1, bd2) -> { int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition()); int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition()); return Integer.compare(i1, i2); }); // 嘗試檢測自定義的 BeanNameGenerator SingletonBeanRegistry sbr = null; if (registry instanceof SingletonBeanRegistry) { sbr = (SingletonBeanRegistry) registry; if (!this.localBeanNameGeneratorSet) { BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR); if (generator != null) { this.componentScanBeanNameGenerator = generator; this.importBeanNameGenerator = generator; } } } // web環境這裏都設置了StandardServletEnvironment //正常狀況下env環境不可能爲null(此處作容錯處理) if (this.environment == null) { this.environment = new StandardEnvironment(); } // ConfigurationClassParser是真正解析@Configuration註解的類 ConfigurationClassParser parser = new ConfigurationClassParser( this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, this.componentScanBeanNameGenerator, registry); // 表示將要被處理的候選配置類 // 由於不清楚候選是否確實是配置類,因此使用BeanDefinitionHolder類型記錄 // 這裏初始化爲方法開始時容器中註解了@Configuration的Bean定義的集合 Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates); // 裝載已經處理過的配置類,最大長度爲:configCandidates.size() // 表示已經處理的配置類,已經被處理的配置類已經明確了其類型,因此用 ConfigurationClass 類型記錄, Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size()); do { // 解析目標配置類【第一個解析的是應用程序主類】 parser.parse(candidates); // 主要校驗配置類不能使用final修飾符(CGLIB代理是生成一個子類,所以原先的類不能使用final修飾) parser.validate(); // 從分析器parser中獲取分析獲得的配置類configurationClasses Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses()); configClasses.removeAll(alreadyParsed); // 若是Reader爲null,那就實例化ConfigurationClassBeanDefinitionReader來加載Bean, // 並加入到alreadyParsed中,用於去重(避免@ComponentScan直接互掃) if (this.reader == null) { this.reader = new ConfigurationClassBeanDefinitionReader( registry, this.sourceExtractor, this.resourceLoader, this.environment, this.importBeanNameGenerator, parser.getImportRegistry()); } // 此處調用ConfigurationClassBeanDefinitionReader的loadBeanDefinitionsd方法 // 加載配置文件裏面的@Bean/@Import,此方法決定了向容器註冊Bean定義信息的順序 this.reader.loadBeanDefinitions(configClasses); // 剛剛處理完的配置類記錄到已處理配置類alreadyParsed集合中 alreadyParsed.addAll(configClasses); // 清空候選配置類集合,爲下一輪do循環作初始化準備 candidates.clear(); // 若是registry中註冊的bean的數量 大於 以前得到的數量 if (registry.getBeanDefinitionCount() > candidateNames.length) { // 則意味着在解析過程當中發現並註冊了更多的Bean定義到容器中去,這些新註冊的Bean定義 // 也有多是候選配置類,它們也要被處理用來發現和註冊Bean定義 String[] newCandidateNames = registry.getBeanDefinitionNames(); Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames)); Set<String> alreadyParsedClasses = new HashSet<>(); for (ConfigurationClass configurationClass : alreadyParsed) { alreadyParsedClasses.add(configurationClass.getMetadata().getClassName()); } for (String candidateName : newCandidateNames) { // 若是老的oldCandidateNames不包含就說明是新進來的候選的Bean定義(即當前 BeanDefinition 是新解析的) if (!oldCandidateNames.contains(candidateName)) { BeanDefinition bd = registry.getBeanDefinition(candidateName); if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) && !alreadyParsedClasses.contains(bd.getBeanClassName())) { // 基於 BeanDefinition 建立 BeanDefinitionHolder 並將其寫入 candidates candidates.add(new BeanDefinitionHolder(bd, candidateName)); } } } candidateNames = newCandidateNames; } } while (!candidates.isEmpty());// 直到全部的配置類都解析完畢 // 註冊 ImportRegistry bean 到 SingletonBeanRegistry 中 if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) { sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry()); } //清除緩存(元數據緩存) if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) { ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache(); } }
下面文章主要圍繞processConfigBeanDefinitions方法作的擴展延伸。
處理配置類並註冊BeanDefinition的方法比較複雜,下面針對方法中一些重要的功能點進行解析:
3.2. 介紹ConfigurationClassUtils工具類
3.3. 解析Java配置類ConfigurationClassParser#parse(Set<BeanDefinitionHolder> configCandidates)
3.3.1 processConfigurationClass解析單個配置類 3.3.1.1 doProcessConfigurationClass 3.3.1.1.1 processMemberClasses 3.3.1.1.2 處理給定的@PropertySource 註解元數據 3.3.1.1.3 @ComponentScan註解解析過程 3.3.1.1.3 processImports 3.3.1.1.5 processInterfaces 3.3.1.2 ConditionEvaluator條件評估 3.3.1.3 ConfigurationClass配置類 3.3.1.4 ConditionalOnProperty
3.4. loadBeanDefinitions加載bean定義信息
ConfigurationClassUtils工具類用於檢查是不是含有@Configuration註解的類,須要注意下面兩個核心方法,是如何判斷某個類是否爲配置類的(判斷是full模式,仍是lite模式的配置文件):
abstract class ConfigurationClassUtils { private static final String CONFIGURATION_CLASS_FULL = "full"; private static final String CONFIGURATION_CLASS_LITE = "lite"; private static final String CONFIGURATION_CLASS_ATTRIBUTE = Conventions.getQualifiedAttributeName(ConfigurationClassPostProcessor.class, "configurationClass"); private static final String ORDER_ATTRIBUTE = Conventions.getQualifiedAttributeName(ConfigurationClassPostProcessor.class, "order"); private static final Log logger = LogFactory.getLog(ConfigurationClassUtils.class); private static final Set<String> candidateIndicators = new HashSet<>(4); static { candidateIndicators.add(Component.class.getName()); candidateIndicators.add(ComponentScan.class.getName()); candidateIndicators.add(Import.class.getName()); candidateIndicators.add(ImportResource.class.getName()); } // 只要這個類標註了:@Configuration註解就行(接口、抽象類都沒問題) public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) { return metadata.isAnnotated(Configuration.class.getName()); } // 判斷是Lite模式的條件:(首先確定沒有@Configuration註解) // 一、不能是接口 // 二、但凡只要標註了一個下面註解,都算lite模式:@Component @ComponentScan @Import @ImportResource // 三、只要存在有一個方法標註了@Bean註解,那就是lite模式 public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata) { // 不能是接口 if (metadata.isInterface()) { return false; } // 但凡只有標註了一個下面註解,都算lite模式:@Component @ComponentScan @Import @ImportResource for (String indicator : candidateIndicators) { if (metadata.isAnnotated(indicator)) { return true; } } // 只有存在有一個方法標註了@Bean註解,那就是lite模式 try { return metadata.hasAnnotatedMethods(Bean.class.getName()); } catch (Throwable ex) { if (logger.isDebugEnabled()) { logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex); } return false; } } // 無論是Full模式仍是Lite模式,都被認爲是候選的配置類,是上面兩個方法的結合 public static boolean isConfigurationCandidate(AnnotationMetadata metadata) { return (isFullConfigurationCandidate(metadata) || isLiteConfigurationCandidate(metadata)); } // 下面兩個方法是直接判斷Bean定義信息,是不是配置類,至於Bean定義裏這個屬性何時放進去的,請參考 //ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)方法, //它會對每一個Bean定義信息進行檢測(畢竟剛開始Bean定義信息是很是少的,因此速度也很快) public static boolean isFullConfigurationClass(BeanDefinition beanDef) { return CONFIGURATION_CLASS_FULL.equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE)); } public static boolean isLiteConfigurationClass(BeanDefinition beanDef) { return CONFIGURATION_CLASS_LITE.equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE)); }
Full模式和Lite模式的區別:
例如:
@Configuration public class AppConfig { @Bean public Foo foo() { return new Foo(bar()); // 這裏調用的bar()方法 } @Bean public Bar bar() { return new Bar(); } }
Foo 接受一個bar的引用來進行構造器注入:這種方法聲明的bean的依賴關係只有在@Configuration類的@Bean方法中有效。若是換成@Component(Lite模式),則foo()方法中new Foo(bar())傳入的bar()方法會每次產生一個新的Bar對象
結論:
在@Component或其餘組建中使用@Bean好處是不會啓動CGLIB這種重量級工具(不過在Spring中即便這裏不使用,其餘不少地方也在使用)。而且@Component及其相關的Stereotype組件自身就有摸框級別的功能,在這裏使用@Bean註解能很好的代表一個Bean的從屬和結構關係,可是須要注意直接調用方法的「反作用」。
我的建議若是沒什麼特別的要求就使用@Configuration,引入CGLIB並不會影響多少性能,然而坑會少不少。在spring官網將用@Configuration建立的@Bean稱呼爲"Full"模式、將@Component建立的@Bean稱呼爲"'lite"模式,從字面上也能略知他們的差別。
只有類上標註@Configuration纔是full模式。標註有@Component、@ComponentScan、@Import、@ImportResource或者啥註解都沒標註可是有被標註了@Bean的方法這種也是lite模式
解過程當中
ConfigurationClassParser#parse
public void parse(Set<BeanDefinitionHolder> configCandidates) { this.deferredImportSelectors = new LinkedList<>(); for (BeanDefinitionHolder holder : configCandidates) { BeanDefinition bd = holder.getBeanDefinition(); // 下面三種方式解析Bean try { // 咱們使用的註解驅動,因此會到這個parse進來處理。 if (bd instanceof AnnotatedBeanDefinition) { // 其實內部調用都是processConfigurationClass進行解析的 parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName()); } //只要有註解標註的,都會走這裏來解析 else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) { parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName()); } else { parse(bd.getBeanClassName(), holder.getBeanName()); } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex); } } //處理ImportSelect,執行找到的 DeferredImportSelector //DeferredImportSelector 是 ImportSelector 的一個變種。 // ImportSelector 被設計成其實和@Import註解的類一樣的導入效果,可是實現 ImportSelector // 的類能夠條件性地決定導入哪些配置。 // DeferredImportSelector 的設計目的是在全部其餘的配置類被處理後才處理。這也正是 // 該語句被放到本函數最後一行的緣由。 processDeferredImportSelectors(); }
該方法作了三件事以下:
解析@Configuration配置文件,而後加載進Bean的定義信息。能夠看到它加載Bean定義信息的一個順序
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException { //ConfigurationCondition繼承自Condition接口 // ConfigurationPhase枚舉類型的做用:根據條件來判斷是否加載這個配置類 // 兩個值:PARSE_CONFIGURATION 若條件不匹配就不加載此@Configuration // REGISTER_BEAN:不管如何,全部@Configurations都將被解析。 if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) { return; } //判斷同一個配置類是否重複加載過,若是重複加載過 ConfigurationClass existingClass = this.configurationClasses.get(configClass); if (existingClass != null) { if (configClass.isImported()) { //若是這個配置類已經存在了,後面又被@Import進來了就會走這裏,而後作屬性合併 if (existingClass.isImported()) { existingClass.mergeImportedBy(configClass); } return; } else { //從集合中移除舊的配置類,後續邏輯將處理新的配置 this.configurationClasses.remove(configClass); this.knownSuperclasses.values().removeIf(configClass::equals); } } SourceClass sourceClass = asSourceClass(configClass); do { //【doProcessConfigurationClass】這個方法是解析配置文件的核心方法 sourceClass = doProcessConfigurationClass(configClass, sourceClass); } while (sourceClass != null); //保存咱們全部的配置類(注意:它是一個LinkedHashMap,因此是有序的和bean定義信息息息相關) this.configurationClasses.put(configClass, configClass); }
doProcessConfigurationClass方法主要實現從配置類中解析全部bean,包括處理內部類,父類以及各類註解
@Nullable protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { //配置類上存在 Component註解,則嘗試遞歸處理其內部成員類 if (configClass.getMetadata().isAnnotated(Component.class.getName())) { processMemberClasses(configClass, sourceClass); } //處理全部 @PropertySource 註解:將目標資源導入到 environment.propertySources 中 //將全部的 @PropertySource 註解合併到 @PropertySources 註解中,並逐個進行處理 for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), PropertySources.class, org.springframework.context.annotation.PropertySource.class)) { if (this.environment instanceof ConfigurableEnvironment) { processPropertySource(propertySource); } else { logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() + "]. Reason: Environment must implement ConfigurableEnvironment"); } } //處理全部的 ComponentScan 註解 //以深度優先的方式遞歸處理全部掃描到的配置類 Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class); if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) { //循環處理每一個 ComponentScan 註解 for (AnnotationAttributes componentScan : componentScans) { //若是此配置類存在ComponentScan註解,則經過 ComponentScanAnnotationParser當即處理它 Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()); // 遍歷掃描到的全部組件 for (BeanDefinitionHolder holder : scannedBeanDefinitions) { //若果掃描出的bean定義是配置類(含有@COnfiguration) if (ConfigurationClassUtils.checkConfigurationClassCandidate( holder.getBeanDefinition(), this.metadataReaderFactory)) { //繼續調用parse,內部再次調用doProcessConfigurationClas()遞歸解析 parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName()); } } } } //處理全部的 @Import 註解 //1.優先處理全部註解上的 @Import 註解導入的配置類 //2.後處理此類上經過@Import 註解直接導入的配置類 processImports(configClass, sourceClass, getImports(sourceClass), true); //處理@ImportResource註解 AnnotationAttributes importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class); if (importResource != null) { // 讀取資源位置 String[] resources = importResource.getStringArray("locations"); // 讀取 BeanDefinitionReader Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader"); for (String resource : resources) { // 解析佔位符 String resolvedResource = this.environment.resolveRequiredPlaceholders(resource); // 寫入緩存 configClass.addImportedResource(resolvedResource, readerClass); } } //處理全部的 @Bean 方法,將它們解析爲 BeanMethod 並寫入配置類中 Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass); for (MethodMetadata methodMetadata : beanMethods) { //將解析出的全部@Bean註解方法添加到configClass配置類信息中 configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); } //處理全部接口上非 Abstract 的 @Bean 方法,並添加到configClass配置類信息中 processInterfaces(configClass, sourceClass); // 若是有父類,則返回父類,遞歸執行doProcessConfigurationClass()解析父類 if (sourceClass.getMetadata().hasSuperClass()) { String superclass = sourceClass.getMetadata().getSuperClassName(); if (superclass != null && !superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) { // 已處理的父類緩存 this.knownSuperclasses.put(superclass, configClass); return sourceClass.getSuperClass(); } } // 此配置類處理完成 return null; }
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { // 讀取全部的成員類 Collection<SourceClass> memberClasses = sourceClass.getMemberClasses(); // 存在成員類 if (!memberClasses.isEmpty()) { List<SourceClass> candidates = new ArrayList<>(memberClasses.size()); for (SourceClass memberClass : memberClasses) { // 過濾出全部的配置類 if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) && !memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) { candidates.add(memberClass); } } // 根據 Order 進行排序 OrderComparator.sort(candidates); for (SourceClass candidate : candidates) { // 出現配置類循環導入 if (this.importStack.contains(configClass)) { this.problemReporter.error(new CircularImportProblem(configClass, this.importStack)); } else { //將此配置類入棧 this.importStack.push(configClass); try { // 處理此配置類 processConfigurationClass(candidate.asConfigClass(configClass)); } finally { //解析完成後將其出棧 this.importStack.pop(); } } } } }
private void processPropertySource(AnnotationAttributes propertySource) throws IOException { // 讀取名稱 String name = propertySource.getString("name"); if (!StringUtils.hasLength(name)) { name = null; } // 讀取編碼 String encoding = propertySource.getString("encoding"); if (!StringUtils.hasLength(encoding)) { encoding = null; } // 讀取資源位置 String[] locations = propertySource.getStringArray("value"); Assert.isTrue(locations.length > 0, "At least one @PropertySource(value) location is required"); // 讀取資源未找到則忽略標識 boolean ignoreResourceNotFound = propertySource.getBoolean("ignoreResourceNotFound"); // 讀取 PropertySourceFactory Class<? extends PropertySourceFactory> factoryClass = propertySource.getClass("factory"); PropertySourceFactory factory = (factoryClass == PropertySourceFactory.class ? DEFAULT_PROPERTY_SOURCE_FACTORY : BeanUtils.instantiateClass(factoryClass)); // 循環處理每一個資源 for (String location : locations) { try { // 解析佔位符 String resolvedLocation = this.environment.resolveRequiredPlaceholders(location); // 讀取資源 Resource resource = this.resourceLoader.getResource(resolvedLocation); // 建立 ResourcePropertySource 並加入到 environment 中 addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding))); } catch (IllegalArgumentException | FileNotFoundException | UnknownHostException ex) { // 佔位符解析失敗或資源未找到 if (ignoreResourceNotFound) { if (logger.isInfoEnabled()) { logger.info("Properties location [" + location + "] not resolvable: " + ex.getMessage()); } } else { throw ex; } } } }
@ComponentScan註解解析經過調用ComponentScanAnnotationParser的parse方法完成,而parse()方法內部處理了一些scanner屬性(過濾器設置)和basePackages包名處理,最終經過調用ClassPathBeanDefinitionScanner.doScan方法實現掃面工做。
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Repeatable(ComponentScans.class) public @interface ComponentScan { /** * 基礎包名稱 */ @AliasFor("basePackages") String[] value() default {}; /** * 基礎包名稱 */ @AliasFor("value") String[] basePackages() default {}; /** * 基礎包類【讀取指定類所在的包路徑】 */ Class<?>[] basePackageClasses() default {}; /** * 用於生成 bean 名稱的 BeanNameGenerator */ Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class; /** * 範圍解析器 */ Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class; /** * 是否須要爲目標組件生成代理,默認不生成 */ ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT; /** * 資源模式 */ String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN; /** * 是否使用默認的過濾器 * 自動檢測 @Component、@Repository、@Service、@Controller 註解標註的類 */ boolean useDefaultFilters() default true; /** * 指定掃描哪些類型 */ Filter[] includeFilters() default {}; /** * 指定排除哪些類型 */ Filter[] excludeFilters() default {}; /** * 掃描到的單例 bean 是否須要延遲初始化 */ boolean lazyInit() default false; @Retention(RetentionPolicy.RUNTIME) @Target({}) @interface Filter { /** * 過濾類型,默認是基於註解 */ FilterType type() default FilterType.ANNOTATION; /** * 用做篩選器的類,多個類之間是邏輯或的關係 */ @AliasFor("classes") Class<?>[] value() default {}; /** * 用做篩選器的類,多個類之間是邏輯或的關係 */ @AliasFor("value") Class<?>[] classes() default {}; /** * 匹配模式,根據 FilterType 分流 */ String[] pattern() default {}; } }
/** * @ComponentScan 註解解析器 */ class ComponentScanAnnotationParser { private final Environment environment; private final ResourceLoader resourceLoader; private final BeanNameGenerator beanNameGenerator; private final BeanDefinitionRegistry registry; public ComponentScanAnnotationParser(Environment environment, ResourceLoader resourceLoader, BeanNameGenerator beanNameGenerator, BeanDefinitionRegistry registry) { this.environment = environment; this.resourceLoader = resourceLoader; this.beanNameGenerator = beanNameGenerator; this.registry = registry; } /** * 解析指定的 @ComponentScan 註解 */ public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) { // 類路徑 BeanDefinition 掃描器 final ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry, componentScan.getBoolean("useDefaultFilters"), environment, resourceLoader); // 設置掃描器的 BeanNameGenerator final Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator"); final boolean useInheritedGenerator = BeanNameGenerator.class == generatorClass; scanner.setBeanNameGenerator(useInheritedGenerator ? beanNameGenerator : BeanUtils.instantiateClass(generatorClass)); // 嘗試設置掃描器的 ScopedProxyMode final ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy"); if (scopedProxyMode != ScopedProxyMode.DEFAULT) { scanner.setScopedProxyMode(scopedProxyMode); } else { final Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver"); scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass)); } // 設置掃描器的資源模式 scanner.setResourcePattern(componentScan.getString("resourcePattern")); // 添加包含過濾器,默認無 for (final AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) { for (final TypeFilter typeFilter : typeFiltersFor(filter)) { scanner.addIncludeFilter(typeFilter); } } // 添加排序過濾器 for (final AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) { for (final TypeFilter typeFilter : typeFiltersFor(filter)) { scanner.addExcludeFilter(typeFilter); } } // 設置延遲初始化屬性 final boolean lazyInit = componentScan.getBoolean("lazyInit"); if (lazyInit) { scanner.getBeanDefinitionDefaults().setLazyInit(true); } final Set<String> basePackages = new LinkedHashSet<>(); // 嘗試讀取 basePackages 屬性 final String[] basePackagesArray = componentScan.getStringArray("basePackages"); for (final String pkg : basePackagesArray) { // 解析佔位符,並按照 ,;\t\n 切割包路徑 final String[] tokenized = StringUtils.tokenizeToStringArray(environment.resolvePlaceholders(pkg), ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); Collections.addAll(basePackages, tokenized); } // 讀取 basePackageClasses,並提取出包路徑 for (final Class<?> clazz : componentScan.getClassArray("basePackageClasses")) { basePackages.add(ClassUtils.getPackageName(clazz)); } /** * 若是 basePackages 和 basePackageClasses 都未配置, * 則以 @ComponentScan 註解所在配置類的包路徑做爲基礎包 */ if (basePackages.isEmpty()) { basePackages.add(ClassUtils.getPackageName(declaringClass)); } // 忽略此配置類 scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) { @Override protected boolean matchClassName(String className) { return declaringClass.equals(className); } }); // 執行包掃描 return scanner.doScan(StringUtils.toStringArray(basePackages)); } private List<TypeFilter> typeFiltersFor(AnnotationAttributes filterAttributes) { final List<TypeFilter> typeFilters = new ArrayList<>(); // 讀取過濾類型 final FilterType filterType = filterAttributes.getEnum("type"); // 讀取全部的 classes for (final Class<?> filterClass : filterAttributes.getClassArray("classes")) { switch (filterType) { // 1)過濾類型爲基於註解 case ANNOTATION: // 目標 class 是不是註解 Assert.isAssignable(Annotation.class, filterClass, "@ComponentScan ANNOTATION type filter requires an annotation type"); @SuppressWarnings("unchecked") final Class<Annotation> annotationType = (Class<Annotation>) filterClass; // 添加註解類型過濾器 typeFilters.add(new AnnotationTypeFilter(annotationType)); break; // 2)過濾類型爲基於目標類型及其子類 case ASSIGNABLE_TYPE: // 添加類型過濾器 typeFilters.add(new AssignableTypeFilter(filterClass)); break; // 3)過濾類型爲基於自定義過濾器 case CUSTOM: // 添加自定義 TypeFilter Assert.isAssignable(TypeFilter.class, filterClass, "@ComponentScan CUSTOM type filter requires a TypeFilter implementation"); final TypeFilter filter = BeanUtils.instantiateClass(filterClass, TypeFilter.class); ParserStrategyUtils.invokeAwareMethods( filter, environment, resourceLoader, registry); typeFilters.add(filter); break; default: throw new IllegalArgumentException("Filter type not supported with Class value: " + filterType); } } // 若是指定了匹配模式 for (final String expression : filterAttributes.getStringArray("pattern")) { switch (filterType) { // 過濾類型爲 ASPECTJ case ASPECTJ: typeFilters.add(new AspectJTypeFilter(expression, resourceLoader.getClassLoader())); break; // 過濾類型爲 REGEX case REGEX: typeFilters.add(new RegexPatternTypeFilter(Pattern.compile(expression))); break; default: throw new IllegalArgumentException("Filter type not supported with String pattern: " + filterType); } } return typeFilters; } }
//ClassPathBeanDefinitionScanner#執行包掃描 protected Set<BeanDefinitionHolder> doScan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); final Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>(); for (final String basePackage : basePackages) { //根據basePackage加載包下全部java文件,並掃描出全部bean組件, //findCandidateComponents方法內部調用 //ClassPathScanningCandidateComponentProvider.scanCandidateComponents(backPackages) final Set<BeanDefinition> candidates = findCandidateComponents(basePackage); //遍歷beandefition for (final BeanDefinition candidate : candidates) { //解析做用域Scope final ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(candidate); candidate.setScope(scopeMetadata.getScopeName()); final String beanName = beanNameGenerator.generateBeanName(candidate, registry); if (candidate instanceof AbstractBeanDefinition) { // 應用默認配置 postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); } //通用註解解析到candidate結構中,主要是處理Lazy, primary DependsOn, Role ,Description這五個註解 if (candidate instanceof AnnotatedBeanDefinition) { // 處理 BeanDefinition 相關注解 AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); } //檢查當前bean是否已經註冊,不存在則註冊 if (checkCandidate(beanName, candidate)) { // 建立 BeanDefinitionHolder BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); // 嘗試應用代理模式 definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, registry); // 添加到 beanDefinitions 進行循環處理 beanDefinitions.add(definitionHolder); // 註冊到ioc容器中,主要是一些@Component組件,@Bean註解方法並無在此處註冊, // definitionHolder: beanname和beandefinition 鍵值對 registerBeanDefinition(definitionHolder, registry); } } } return beanDefinitions; }
public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) { processCommonDefinitionAnnotations(abd, abd.getMetadata()); } static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) { // 1)目標元素存在 @Lazy 註解 AnnotationAttributes lazy = attributesFor(metadata, Lazy.class); if (lazy != null) { abd.setLazyInit(lazy.getBoolean("value")); } else if (abd.getMetadata() != metadata) { lazy = attributesFor(abd.getMetadata(), Lazy.class); if (lazy != null) { abd.setLazyInit(lazy.getBoolean("value")); } } // 2)目標元素存在 @Primary 註解 if (metadata.isAnnotated(Primary.class.getName())) { abd.setPrimary(true); } // 3)目標元素存在 @DependsOn 註解 final AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class); if (dependsOn != null) { abd.setDependsOn(dependsOn.getStringArray("value")); } // 4)目標元素存在 @Role 註解 final AnnotationAttributes role = attributesFor(metadata, Role.class); if (role != null) { abd.setRole(role.getNumber("value").intValue()); } // 5)目標元素存在 @Description 註解 final AnnotationAttributes description = attributesFor(metadata, Description.class); if (description != null) { abd.setDescription(description.getString("value")); } } static BeanDefinitionHolder applyScopedProxyMode( ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) { // 讀取代理模式 final ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode(); if (scopedProxyMode.equals(ScopedProxyMode.NO)) { return definition; } // 若是是基於 CGLIB 的類代理 final boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS); return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass); }
//掃描指定的類路徑 public Set<BeanDefinition> findCandidateComponents(String basePackage) { if (componentsIndex != null && indexSupportsIncludeFilters()) { return addCandidateComponentsFromIndex(componentsIndex, basePackage); } else { // 掃描組件 return scanCandidateComponents(basePackage); } } //實現bean定義信息掃描 private Set<BeanDefinition> scanCandidateComponents(String basePackage) { final Set<BeanDefinition> candidates = new LinkedHashSet<>(); try { // @ComponentScan("com.sl.springlearning.extension")包路徑處理: // packageSearchPath = classpath*:com/sl/springlearning/extension/**/*.class final String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolveBasePackage(basePackage) + '/' + resourcePattern; // 經過 ServletContextResourcePatternResolver 讀取全部資源(當前包下全部的class文件) final Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath); final boolean traceEnabled = logger.isTraceEnabled(); final boolean debugEnabled = logger.isDebugEnabled(); // 循環處理全部資源 for (final Resource resource : resources) { if (traceEnabled) { logger.trace("Scanning " + resource); } // 資源是可讀取的 if (resource.isReadable()) { try { // 讀取 MetadataReader final MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource); //按照scanner過濾器過濾,好比配置類自己將被過濾掉,沒有@Component等組件註解的類將過濾掉 if (isCandidateComponent(metadataReader)) { // 基於 MetadataReader 建立 ScannedGenericBeanDefinition final ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader); sbd.setResource(resource); sbd.setSource(resource); // 是不是候選組件 if (isCandidateComponent(sbd)) { if (debugEnabled) { logger.debug("Identified candidate component class: " + resource); } candidates.add(sbd); } else { if (debugEnabled) { logger.debug("Ignored because not a concrete top-level class: " + resource); } } } else { if (traceEnabled) { logger.trace("Ignored because not matching any filter: " + resource); } } } catch (final Throwable ex) { throw new BeanDefinitionStoreException( "Failed to read candidate component class: " + resource, ex); } } else { if (traceEnabled) { logger.trace("Ignored because not readable: " + resource); } } } } catch (final IOException ex) { throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex); } return candidates; } /** * 將類名解析爲資源路徑 * 爲了不多餘的替換操做,能夠直接使用 / 做爲包分隔符 */ protected String resolveBasePackage(String basePackage) { return ClassUtils.convertClassNameToResourcePath(getEnvironment().resolveRequiredPlaceholders(basePackage)); } /** * 目標類不匹配任何排除過濾器,而且至少匹配一個包含過濾器 */ protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException { for (final TypeFilter tf : excludeFilters) { // 匹配當期排除過濾器 if (tf.match(metadataReader, getMetadataReaderFactory())) { return false; } } for (final TypeFilter tf : includeFilters) { // 匹配當前包含過濾器 if (tf.match(metadataReader, getMetadataReaderFactory())) { return isConditionMatch(metadataReader); } } return false; } /** * 目標 BeanDefinition 是不是一個候選組件 */ protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { final AnnotationMetadata metadata = beanDefinition.getMetadata(); /** * 目標類型不是接口,而且不依賴於封閉類【不是內部類】 */ return metadata.isIndependent() && (metadata.isConcrete() || metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName())); }
/** * 可配置 ServletContext 的 PathMatchingResourcePatternResolver */ public class ServletContextResourcePatternResolver extends PathMatchingResourcePatternResolver { private static final Log logger = LogFactory.getLog(ServletContextResourcePatternResolver.class); public ServletContextResourcePatternResolver(ServletContext servletContext) { super(new ServletContextResourceLoader(servletContext)); } public ServletContextResourcePatternResolver(ResourceLoader resourceLoader) { super(resourceLoader); } @Override protected Set<Resource> doFindPathMatchingFileResources(Resource rootDirResource, String subPattern) throws IOException { // 若是跟路徑資源是 ServletContextResource if (rootDirResource instanceof ServletContextResource) { final ServletContextResource scResource = (ServletContextResource) rootDirResource; final ServletContext sc = scResource.getServletContext(); final String fullPattern = scResource.getPath() + subPattern; final Set<Resource> result = new LinkedHashSet<>(8); doRetrieveMatchingServletContextResources(sc, fullPattern, scResource.getPath(), result); return result; } else { // 默認是 UrlResource return super.doFindPathMatchingFileResources(rootDirResource, subPattern); } } }
@Override public Resource[] getResources(String locationPattern) throws IOException { Assert.notNull(locationPattern, "Location pattern must not be null"); // 資源路徑以 classpath*: 開頭 if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) { /** * 支持多個同名文件 * a class path resource (multiple resources for same name possible) * 資源路徑是 Ant 風格的通配符 */ if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) { // a class path resource pattern return findPathMatchingResources(locationPattern); } else { // 讀取 classpath 特定根路徑下的全部資源 return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length())); } } else { // Generally only look for a pattern after a prefix here, and on Tomcat only after the "*/" separator for its "war:" protocol. final int prefixEnd = locationPattern.startsWith("war:") ? locationPattern.indexOf("*/") + 1 : locationPattern.indexOf(':') + 1; if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) { // a file pattern return findPathMatchingResources(locationPattern); } else { // a single resource with the given name return new Resource[] {getResourceLoader().getResource(locationPattern)}; } } } /** * 經過 Ant 風格的路徑匹配器查找全部匹配資源 */ protected Resource[] findPathMatchingResources(String locationPattern) throws IOException { // 肯定給定位置的根目錄:classpath*:org/zxd/spring5/ final String rootDirPath = determineRootDir(locationPattern); // 截取模糊匹配路徑:**/*.class final String subPattern = locationPattern.substring(rootDirPath.length()); // 讀取根路徑 Resource final Resource[] rootDirResources = getResources(rootDirPath); final Set<Resource> result = new LinkedHashSet<>(16); // 遍歷全部根路徑 for (Resource rootDirResource : rootDirResources) { rootDirResource = resolveRootDirResource(rootDirResource); // 獲取根路徑 URL URL rootDirUrl = rootDirResource.getURL(); // 1)URL 協議以 bundle 開頭 if (equinoxResolveMethod != null && rootDirUrl.getProtocol().startsWith("bundle")) { final URL resolvedUrl = (URL) ReflectionUtils.invokeMethod(equinoxResolveMethod, null, rootDirUrl); if (resolvedUrl != null) { rootDirUrl = resolvedUrl; } rootDirResource = new UrlResource(rootDirUrl); } // 2)URL 協議以 vfs 開頭 if (rootDirUrl.getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) { result.addAll(VfsResourceMatchingDelegate.findMatchingResources(rootDirUrl, subPattern, getPathMatcher())); } // 3)URL 是一個 jar:jar、war、zip、vfszip、wsjar else if (ResourceUtils.isJarURL(rootDirUrl) || isJarResource(rootDirResource)) { result.addAll(doFindPathMatchingJarResources(rootDirResource, rootDirUrl, subPattern)); } else { // 4)URL 協議以 file 開頭 result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern)); } } if (logger.isTraceEnabled()) { logger.trace("Resolved location pattern [" + locationPattern + "] to resources " + result); } return result.toArray(new Resource[0]); } protected Resource[] findAllClassPathResources(String location) throws IOException { String path = location; if (path.startsWith("/")) { path = path.substring(1); } // 讀取全部的 ClassPathResource final Set<Resource> result = doFindAllClassPathResources(path); if (logger.isTraceEnabled()) { logger.trace("Resolved classpath location [" + location + "] to resources " + result); } return result.toArray(new Resource[0]); } protected Set<Resource> doFindAllClassPathResources(String path) throws IOException { final Set<Resource> result = new LinkedHashSet<>(16); // 讀取類加載器 final ClassLoader cl = getClassLoader(); // 讀取指定包路徑【org/zxd/spring5/】下全部資源的 URL final Enumeration<URL> resourceUrls = cl != null ? cl.getResources(path) : ClassLoader.getSystemResources(path); while (resourceUrls.hasMoreElements()) { final URL url = resourceUrls.nextElement(); result.add(convertClassLoaderURL(url)); } if ("".equals(path)) { // The above result is likely to be incomplete, i.e. only containing file system references. // We need to have pointers to each of the jar files on the classpath as well... addAllClassLoaderJarRoots(cl, result); } return result; } /** * 將 URL 轉換爲 UrlResource */ protected Resource convertClassLoaderURL(URL url) { return new UrlResource(url); }
配置類 BeanDefinition 讀取器
/** * 從一組完整的 ConfigurationClass 類中解析 BeanDefinition * 並將其註冊到 BeanDefinitionRegistry 中。 */ class ConfigurationClassBeanDefinitionReader { private static final Log logger = LogFactory.getLog(ConfigurationClassBeanDefinitionReader.class); private static final ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver(); private final BeanDefinitionRegistry registry; private final SourceExtractor sourceExtractor; private final ResourceLoader resourceLoader; private final Environment environment; private final BeanNameGenerator importBeanNameGenerator; private final ImportRegistry importRegistry; private final ConditionEvaluator conditionEvaluator; /** * Create a new {@link ConfigurationClassBeanDefinitionReader} instance * that will be used to populate the given {@link BeanDefinitionRegistry}. */ ConfigurationClassBeanDefinitionReader(BeanDefinitionRegistry registry, SourceExtractor sourceExtractor, ResourceLoader resourceLoader, Environment environment, BeanNameGenerator importBeanNameGenerator, ImportRegistry importRegistry) { registry = registry; sourceExtractor = sourceExtractor; resourceLoader = resourceLoader; environment = environment; importBeanNameGenerator = importBeanNameGenerator; importRegistry = importRegistry; conditionEvaluator = new ConditionEvaluator(registry, environment, resourceLoader); } /** * 從已解析的 ConfigurationClass 中讀取 BeanDefinition */ public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) { TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator(); for (ConfigurationClass configClass : configurationModel) { loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator); } } /** * 讀取一個特定的 ConfigurationClass 並註冊 BeanDefinition */ private void loadBeanDefinitionsForConfigurationClass( ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) { // 是否須要忽略此配置類 if (trackedConditionEvaluator.shouldSkip(configClass)) { String beanName = configClass.getBeanName(); // 將其從 BeanDefinitionRegistry 中移除 if (StringUtils.hasLength(beanName) && registry.containsBeanDefinition(beanName)) { registry.removeBeanDefinition(beanName); } // 將此類從 importRegistry 中移除 importRegistry.removeImportingClass(configClass.getMetadata().getClassName()); return; } // 1)此配置類是經過 @Import 導入的 if (configClass.isImported()) { registerBeanDefinitionForImportedConfigurationClass(configClass); } // 2)處理全部經過 @Bean 註解的方法 for (BeanMethod beanMethod : configClass.getBeanMethods()) { loadBeanDefinitionsForBeanMethod(beanMethod); } // 解析經過 @ImportResource 導入的配置文件 loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()); // 解析經過 @Import 導入的 ImportBeanDefinitionRegistrar loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); } /** * 將配置類自己註冊到 BeanDefinitionRegistry 中 */ private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) { AnnotationMetadata metadata = configClass.getMetadata(); AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata); ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef); configBeanDef.setScope(scopeMetadata.getScopeName()); String configBeanName = importBeanNameGenerator.generateBeanName(configBeanDef, registry); AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata); BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, registry); registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition()); configClass.setBeanName(configBeanName); if (logger.isTraceEnabled()) { logger.trace("Registered bean definition for imported class '" + configBeanName + "'"); } } @SuppressWarnings("deprecation") // for RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) { ConfigurationClass configClass = beanMethod.getConfigurationClass(); MethodMetadata metadata = beanMethod.getMetadata(); // 讀取方法名稱 String methodName = metadata.getMethodName(); // 此 Bean 是否已經被忽略 if (configClass.skippedBeanMethods.contains(methodName)) { return; } // 此 Bean 是否須要忽略 if (conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) { configClass.skippedBeanMethods.add(methodName); return; } // 讀取 @Bean 註解的屬性 AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class); Assert.state(bean != null, "No @Bean annotation attributes"); // 讀取 bean 名稱 List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name"))); // 若是配置了 bean 名稱,則獲取第一個;不然以方法名稱做爲 bean 的名稱 String beanName = !names.isEmpty() ? names.remove(0) : methodName; // 嘗試註冊別名 for (String alias : names) { registry.registerAlias(beanName, alias); } // Has this effectively been overridden before (e.g. via XML)? if (isOverriddenByExistingDefinition(beanMethod, beanName)) { if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) { throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(), beanName, "Bean name derived from @Bean method '" + beanMethod.getMetadata().getMethodName() + "' clashes with bean name for containing configuration class; please make those names unique!"); } return; } // 建立 ConfigurationClassBeanDefinition ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata); beanDef.setResource(configClass.getResource()); beanDef.setSource(sourceExtractor.extractSource(metadata, configClass.getResource())); // @Bean 標註的方法是靜態方法 if (metadata.isStatic()) { // static @Bean method beanDef.setBeanClassName(configClass.getMetadata().getClassName()); beanDef.setFactoryMethodName(methodName); } // @Bean 標註的方法是實例方法 else { // instance @Bean method beanDef.setFactoryBeanName(configClass.getBeanName()); beanDef.setUniqueFactoryMethodName(methodName); } // 配置屬性 beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR); beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor. SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE); // 處理通用 BeanDefinition 註解 AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata); // 寫入 Autowire Autowire autowire = bean.getEnum("autowire"); if (autowire.isAutowire()) { beanDef.setAutowireMode(autowire.value()); } // 寫入 AutowireCandidate boolean autowireCandidate = bean.getBoolean("autowireCandidate"); if (!autowireCandidate) { beanDef.setAutowireCandidate(false); } // 寫入初始化方法 String initMethodName = bean.getString("initMethod"); if (StringUtils.hasText(initMethodName)) { beanDef.setInitMethodName(initMethodName); } // 寫入銷燬方法 String destroyMethodName = bean.getString("destroyMethod"); beanDef.setDestroyMethodName(destroyMethodName); // Consider scoping ScopedProxyMode proxyMode = ScopedProxyMode.NO; AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class); if (attributes != null) { beanDef.setScope(attributes.getString("value")); 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), registry, proxyMode == ScopedProxyMode.TARGET_CLASS); beanDefToRegister = new ConfigurationClassBeanDefinition( (RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata); } if (logger.isTraceEnabled()) { logger.trace(String.format("Registering bean definition for @Bean method %s.%s()", configClass.getMetadata().getClassName(), beanName)); } // 註冊此 BeanDefinition registry.registerBeanDefinition(beanName, beanDefToRegister); } protected boolean isOverriddenByExistingDefinition(BeanMethod beanMethod, String beanName) { if (!registry.containsBeanDefinition(beanName)) { return false; } BeanDefinition existingBeanDef = registry.getBeanDefinition(beanName); // Is the existing bean definition one that was created from a configuration class? // -> allow the current bean method to override, since both are at second-pass level. // However, if the bean method is an overloaded case on the same configuration class, // preserve the existing bean definition. if (existingBeanDef instanceof ConfigurationClassBeanDefinition) { ConfigurationClassBeanDefinition ccbd = (ConfigurationClassBeanDefinition) existingBeanDef; return ccbd.getMetadata().getClassName().equals( beanMethod.getConfigurationClass().getMetadata().getClassName()); } // A bean definition resulting from a component scan can be silently overridden // by an @Bean method, as of 4.2... if (existingBeanDef instanceof ScannedGenericBeanDefinition) { return false; } // Has the existing bean definition bean marked as a framework-generated bean? // -> allow the current bean method to override it, since it is application-level if (existingBeanDef.getRole() > BeanDefinition.ROLE_APPLICATION) { return false; } // At this point, it's a top-level override (probably XML), just having been parsed // before configuration class processing kicks in... if (registry instanceof DefaultListableBeanFactory && !((DefaultListableBeanFactory) registry).isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(), beanName, "@Bean definition illegally overridden by existing bean definition: " + existingBeanDef); } if (logger.isDebugEnabled()) { logger.debug(String.format("Skipping bean definition for %s: a definition for bean '%s' " + "already exists. This top-level bean definition is considered as an override.", beanMethod, beanName)); } return true; } private void loadBeanDefinitionsFromImportedResources( Map<String, Class<? extends BeanDefinitionReader>> importedResources) { Map<Class<?>, BeanDefinitionReader> readerInstanceCache = new HashMap<>(); importedResources.forEach((resource, readerClass) -> { // 使用默認的 BeanDefinitionReader if (BeanDefinitionReader.class == readerClass) { // 目標資源以 .groovy 結尾,則使用 GroovyBeanDefinitionReader 進行讀取 if (StringUtils.endsWithIgnoreCase(resource, ".groovy")) { // When clearly asking for Groovy, that's what they'll get... readerClass = GroovyBeanDefinitionReader.class; } else { // 不然使用 XmlBeanDefinitionReader 進行讀取 readerClass = XmlBeanDefinitionReader.class; } } // 讀取緩存的 BeanDefinitionReader BeanDefinitionReader reader = readerInstanceCache.get(readerClass); if (reader == null) { try { // 實例化特定的 BeanDefinitionReader reader = readerClass.getConstructor(BeanDefinitionRegistry.class).newInstance(registry); // Delegate the current ResourceLoader to it if possible if (reader instanceof AbstractBeanDefinitionReader) { AbstractBeanDefinitionReader abdr = (AbstractBeanDefinitionReader) reader; abdr.setResourceLoader(resourceLoader); abdr.setEnvironment(environment); } readerInstanceCache.put(readerClass, reader); } catch (Throwable ex) { throw new IllegalStateException( "Could not instantiate BeanDefinitionReader class [" + readerClass.getName() + "]"); } } // 使用 BeanDefinitionReader 讀取 BeanDefinition // TODO SPR-6310: qualify relative path locations as done in AbstractContextLoader.modifyLocations reader.loadBeanDefinitions(resource); }); } /** * 經過 ImportBeanDefinitionRegistrar 註冊 BeanDefinition */ private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) { registrars.forEach((registrar, metadata) -> registrar.registerBeanDefinitions(metadata, registry)); } @SuppressWarnings("serial") private static class ConfigurationClassBeanDefinition extends RootBeanDefinition implements AnnotatedBeanDefinition { /** * 註解元數據 */ private final AnnotationMetadata annotationMetadata; /** * 方法元數據 */ private final MethodMetadata factoryMethodMetadata; public ConfigurationClassBeanDefinition(ConfigurationClass configClass, MethodMetadata beanMethodMetadata) { annotationMetadata = configClass.getMetadata(); factoryMethodMetadata = beanMethodMetadata; setLenientConstructorResolution(false); } public ConfigurationClassBeanDefinition( RootBeanDefinition original, ConfigurationClass configClass, MethodMetadata beanMethodMetadata) { super(original); annotationMetadata = configClass.getMetadata(); factoryMethodMetadata = beanMethodMetadata; } private ConfigurationClassBeanDefinition(ConfigurationClassBeanDefinition original) { super(original); annotationMetadata = original.annotationMetadata; factoryMethodMetadata = original.factoryMethodMetadata; } @Override public AnnotationMetadata getMetadata() { return annotationMetadata; } @Override public MethodMetadata getFactoryMethodMetadata() { return factoryMethodMetadata; } @Override public boolean isFactoryMethod(Method candidate) { return super.isFactoryMethod(candidate) && BeanAnnotationHelper.isBeanAnnotated(candidate); } @Override public ConfigurationClassBeanDefinition cloneBeanDefinition() { return new ConfigurationClassBeanDefinition(this); } } private class TrackedConditionEvaluator { private final Map<ConfigurationClass, Boolean> skipped = new HashMap<>(); public boolean shouldSkip(ConfigurationClass configClass) { Boolean skip = skipped.get(configClass); if (skip == null) { if (configClass.isImported()) { boolean allSkipped = true; for (ConfigurationClass importedBy : configClass.getImportedBy()) { if (!shouldSkip(importedBy)) { allSkipped = false; break; } } if (allSkipped) { // The config classes that imported this one were all skipped, therefore we are skipped... skip = true; } } if (skip == null) { skip = conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN); } skipped.put(configClass, skip); } return skip; } } }
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, boolean checkForCircularImports) { // 若是配置類上沒有任何候選@Import(importCandidates), //說明沒有須要處理的導入,則什麼都不用作,直接返回 if (importCandidates.isEmpty()) { return; } // 進行循環依賴的檢查 if (checkForCircularImports && isChainedImportOnStack(configClass)) { // 若是要求作循環導入檢查,而且檢查到了循環依賴,報告這個問題 this.problemReporter.error(new CircularImportProblem(configClass, this.importStack)); } else { // 開始處理配置類configClass上全部的@Import importCandidates this.importStack.push(configClass); try { // 循環處理每個@Import,每一個@Import可能導入三種類型的類 : // 1. ImportSelector // 2. ImportBeanDefinitionRegistrar // 3. 其餘類型,都看成配置類處理,也就是至關於使用了註解@Configuration的配置類 // 下面的for循環中對這三種狀況執行了不一樣的處理邏輯 for (SourceClass candidate : importCandidates) { // 目標類是 ImportSelector 實例 if (candidate.isAssignable(ImportSelector.class)) { Class<?> candidateClass = candidate.loadClass(); // 建立目標實例 ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class); // 執行 BeanClassLoaderAware、BeanFactoryAware、EnvironmentAware、ResourceLoaderAware 注入 ParserStrategyUtils.invokeAwareMethods( selector, this.environment, this.resourceLoader, this.registry); // 若是這個類也是DeferredImportSelector接口的實現類, // 那麼加入ConfigurationClassParser的deferredImportSelectors if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) { this.deferredImportSelectors.add( new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector)); } else {//若是不是,則調用processImports 進行處理. // 獲取全部配置類名稱 String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); // 獲取全部配置類名稱 Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames); // 遞歸處理全部導入的配置類 processImports(configClass, currentSourceClass, importSourceClasses, false); } } // 若是這個類是ImportBeanDefinitionRegistrar接口的實現類 // 設置到配置類的importBeanDefinitionRegistrars屬性中 else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { Class<?> candidateClass = candidate.loadClass(); // 實例化 ImportBeanDefinitionRegistrar ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class); // 執行 Aware 注入 ParserStrategyUtils.invokeAwareMethods( registrar, this.environment, this.resourceLoader, this.registry); // 寫入 importBeanDefinitionRegistrars 緩存 configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } else { //配置類不是 ImportSelector or ImportBeanDefinitionRegistrar, //則加入到importStack後調用processConfigurationClass 進行處理. // 其它狀況下把這個類入隊到ConfigurationClassParser的importStack(隊列)屬性中 // 而後把這個類當成是@Configuration註解修飾的類遞歸重頭開始解析這個類 this.importStack.registerImport( currentSourceClass.getMetadata(), candidate.getMetadata().getClassName()); processConfigurationClass(candidate.asConfigClass(configClass)); } } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to process import candidates for configuration class [" + configClass.getMetadata().getClassName() + "]", ex); } finally { this.importStack.pop(); } } }
/** * 解析接口上的方法,若是此方法存在 @Bean 註解 */ private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { for (final SourceClass ifc : sourceClass.getInterfaces()) { final Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(ifc); for (final MethodMetadata methodMetadata : beanMethods) { if (!methodMetadata.isAbstract()) { // A default method or other concrete method on a Java 8+ interface... configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); } } processInterfaces(configClass, ifc); } }
用於計算 @Conditional 註解的內部類
class ConditionEvaluator { private final ConditionContextImpl context; public ConditionEvaluator(@Nullable BeanDefinitionRegistry registry, @Nullable Environment environment, @Nullable ResourceLoader resourceLoader) { context = new ConditionContextImpl(registry, environment, resourceLoader); } /** * 指定類或方法上是否存在 @Conditional 註解,並須要跳過處理流程 */ public boolean shouldSkip(AnnotatedTypeMetadata metadata) { return shouldSkip(metadata, null); } public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) { // 註解元數據爲空 || 目標元素不存在 @Conditional 註解,不跳過 if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) { return false; } if (phase == null) { if (metadata instanceof AnnotationMetadata && ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) { return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION); } return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN); } final List<Condition> conditions = new ArrayList<>(); // 讀取全部的條件類 for (final String[] conditionClasses : getConditionClasses(metadata)) { for (final String conditionClass : conditionClasses) { final Condition condition = getCondition(conditionClass, context.getClassLoader()); conditions.add(condition); } } // 根據 Order 進行排序 AnnotationAwareOrderComparator.sort(conditions); for (final Condition condition : conditions) { ConfigurationPhase requiredPhase = null; if (condition instanceof ConfigurationCondition) { requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase(); } // 請求階段爲空或請求階段==此階段 && 此條件不匹配 if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(context, metadata)) { return true; } } // 全部的條件都匹配 return false; } @SuppressWarnings("unchecked") private List<String[]> getConditionClasses(AnnotatedTypeMetadata metadata) { // 讀取全部 @Conditional 註解的屬性配置 final MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes(Conditional.class.getName(), true); // 讀取評估條件 final Object values = attributes != null ? attributes.get("value") : null; return (List<String[]>) (values != null ? values : Collections.emptyList()); } /** * 實例化目標條件 */ private Condition getCondition(String conditionClassName, @Nullable ClassLoader classloader) { final Class<?> conditionClass = ClassUtils.resolveClassName(conditionClassName, classloader); return (Condition) BeanUtils.instantiateClass(conditionClass); } private static class ConditionContextImpl implements ConditionContext { @Nullable private final BeanDefinitionRegistry registry; @Nullable private final ConfigurableListableBeanFactory beanFactory; private final Environment environment; private final ResourceLoader resourceLoader; @Nullable private final ClassLoader classLoader; public ConditionContextImpl(@Nullable BeanDefinitionRegistry registry, @Nullable Environment environment, @Nullable ResourceLoader resourceLoader) { this.registry = registry; beanFactory = deduceBeanFactory(registry); this.environment = environment != null ? environment : deduceEnvironment(registry); this.resourceLoader = resourceLoader != null ? resourceLoader : deduceResourceLoader(registry); classLoader = deduceClassLoader(resourceLoader, beanFactory); } @Nullable private ConfigurableListableBeanFactory deduceBeanFactory(@Nullable BeanDefinitionRegistry source) { if (source instanceof ConfigurableListableBeanFactory) { return (ConfigurableListableBeanFactory) source; } if (source instanceof ConfigurableApplicationContext) { return ((ConfigurableApplicationContext) source).getBeanFactory(); } return null; } /** * 推斷 Environment */ private Environment deduceEnvironment(@Nullable BeanDefinitionRegistry source) { if (source instanceof EnvironmentCapable) { return ((EnvironmentCapable) source).getEnvironment(); } return new StandardEnvironment(); } /** * 推斷 ResourceLoader */ private ResourceLoader deduceResourceLoader(@Nullable BeanDefinitionRegistry source) { if (source instanceof ResourceLoader) { return (ResourceLoader) source; } return new DefaultResourceLoader(); } /** * 推斷 ClassLoader */ @Nullable private ClassLoader deduceClassLoader(@Nullable ResourceLoader resourceLoader, @Nullable ConfigurableListableBeanFactory beanFactory) { if (resourceLoader != null) { final ClassLoader classLoader = resourceLoader.getClassLoader(); if (classLoader != null) { return classLoader; } } if (beanFactory != null) { return beanFactory.getBeanClassLoader(); } return ClassUtils.getDefaultClassLoader(); } @Override public BeanDefinitionRegistry getRegistry() { Assert.state(registry != null, "No BeanDefinitionRegistry available"); return registry; } @Override @Nullable public ConfigurableListableBeanFactory getBeanFactory() { return beanFactory; } @Override public Environment getEnvironment() { return environment; } @Override public ResourceLoader getResourceLoader() { return resourceLoader; } @Override @Nullable public ClassLoader getClassLoader() { return classLoader; } } }
ConfigurationClass表明一個配置類,它內部維護了一些已經解析好的可是尚未被加入進Bean定義信息的原始信息,有必要作以下解釋:
//它是普通的類,基本只有get set方法 final class ConfigurationClass { private final AnnotationMetadata metadata; private final Resource resource; @Nullable private String beanName; private final Set<ConfigurationClass> importedBy = new LinkedHashSet<>(1); // 存儲該配置類裏全部標註@Bean註解的方法~~~~ private final Set<BeanMethod> beanMethods = new LinkedHashSet<>(); // 用Map保存着@ImportResource 導入進來的資源們~ private final Map<String, Class<? extends BeanDefinitionReader>> importedResources = new LinkedHashMap<>(); // 用Map保存着@Import中實現了`ImportBeanDefinitionRegistrar`接口的內容~ private final Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars = new LinkedHashMap<>(); final Set<String> skippedBeanMethods = new HashSet<>(); }
/** * 此 Environment 中是否存在指定的屬性 && 屬性具備存在特定值【若是指定】。 */ @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.TYPE, ElementType.METHOD }) @Documented @Conditional(OnPropertyCondition.class) // 經過 @Conditional 註解關聯條件類 public @interface ConditionalOnProperty { /** * 屬性的名稱 */ String[] value() default {}; /** * 每一個屬性的前綴 */ String prefix() default ""; /** * 屬性的名稱 */ String[] name() default {}; /** * 屬性值 */ String havingValue() default ""; /** * 若是 Environment 中不存在此屬性,是否匹配【默認不匹配】 */ boolean matchIfMissing() default false; } /** * 組件被註冊到 BeanDefinitionRegistry 時必須知足的條件 */ @FunctionalInterface public interface Condition { /** * 判斷此條件是否知足 */ boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata); } public abstract class SpringBootCondition implements Condition { private final Log logger = LogFactory.getLog(getClass()); @Override public final boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { // 讀取類名或方法名稱 String classOrMethodName = getClassOrMethodName(metadata); try { // 讀取條件的輸出結果 ConditionOutcome outcome = getMatchOutcome(context, metadata); // 記錄日誌 logOutcome(classOrMethodName, outcome); // 記錄評估結果 recordEvaluation(context, classOrMethodName, outcome); // 此條件是否知足 return outcome.isMatch(); } catch (NoClassDefFoundError ex) { throw new IllegalStateException( "Could not evaluate condition on " + classOrMethodName + " due to " + ex.getMessage() + " not " + "found. Make sure your own configuration does not rely on " + "that class. This can also happen if you are " + "@ComponentScanning a springframework package (e.g. if you " + "put a @ComponentScan in the default package by mistake)", ex); } catch (RuntimeException ex) { throw new IllegalStateException( "Error processing condition on " + getName(metadata), ex); } } private String getName(AnnotatedTypeMetadata metadata) { if (metadata instanceof AnnotationMetadata) { return ((AnnotationMetadata) metadata).getClassName(); } if (metadata instanceof MethodMetadata) { MethodMetadata methodMetadata = (MethodMetadata) metadata; return methodMetadata.getDeclaringClassName() + "." + methodMetadata.getMethodName(); } return metadata.toString(); } private static String getClassOrMethodName(AnnotatedTypeMetadata metadata) { if (metadata instanceof ClassMetadata) { ClassMetadata classMetadata = (ClassMetadata) metadata; return classMetadata.getClassName(); } MethodMetadata methodMetadata = (MethodMetadata) metadata; return methodMetadata.getDeclaringClassName() + "#" + methodMetadata.getMethodName(); } protected final void logOutcome(String classOrMethodName, ConditionOutcome outcome) { if (this.logger.isTraceEnabled()) { this.logger.trace(getLogMessage(classOrMethodName, outcome)); } } private StringBuilder getLogMessage(String classOrMethodName, ConditionOutcome outcome) { StringBuilder message = new StringBuilder(); message.append("Condition "); message.append(ClassUtils.getShortName(getClass())); message.append(" on "); message.append(classOrMethodName); message.append(outcome.isMatch() ? " matched" : " did not match"); if (StringUtils.hasLength(outcome.getMessage())) { message.append(" due to "); message.append(outcome.getMessage()); } return message; } private void recordEvaluation(ConditionContext context, String classOrMethodName, ConditionOutcome outcome) { if (context.getBeanFactory() != null) { ConditionEvaluationReport.get(context.getBeanFactory()) .recordConditionEvaluation(classOrMethodName, this, outcome); } } /** * 肯定匹配結果 */ public abstract ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata); /** * 只要有一個條件知足 */ protected final boolean anyMatches(ConditionContext context, AnnotatedTypeMetadata metadata, Condition... conditions) { for (Condition condition : conditions) { if (matches(context, metadata, condition)) { return true; } } return false; } /** * 指定的條件是否知足 */ protected final boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata, Condition condition) { if (condition instanceof SpringBootCondition) { return ((SpringBootCondition) condition).getMatchOutcome(context, metadata) .isMatch(); } return condition.matches(context, metadata); } } /** * 指定的屬性是否認義在此 Environment 中 */ @Order(Ordered.HIGHEST_PRECEDENCE + 40) class OnPropertyCondition extends SpringBootCondition { @Override public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { // 讀取目標元素上全部的 @ConditionalOnProperty 註解的屬性信息 final List<AnnotationAttributes> allAnnotationAttributes = annotationAttributesFromMultiValueMap( metadata.getAllAnnotationAttributes(ConditionalOnProperty.class.getName())); final List<ConditionMessage> noMatch = new ArrayList<>(); final List<ConditionMessage> match = new ArrayList<>(); for (final AnnotationAttributes annotationAttributes : allAnnotationAttributes) { // 肯定當前 ConditionalOnProperty 條件的輸出結果 final ConditionOutcome outcome = determineOutcome(annotationAttributes, context.getEnvironment()); // 記錄 ConditionMessage (outcome.isMatch() ? match : noMatch).add(outcome.getConditionMessage()); } // 存在一個不匹配條件 if (!noMatch.isEmpty()) { return ConditionOutcome.noMatch(ConditionMessage.of(noMatch)); } // 全部的條件都匹配 return ConditionOutcome.match(ConditionMessage.of(match)); } private List<AnnotationAttributes> annotationAttributesFromMultiValueMap( MultiValueMap<String, Object> multiValueMap) { final List<Map<String, Object>> maps = new ArrayList<>(); multiValueMap.forEach((key, value) -> { for (int i = 0; i < value.size(); i++) { Map<String, Object> map; if (i < maps.size()) { map = maps.get(i); } else { map = new HashMap<>(); maps.add(map); } map.put(key, value.get(i)); } }); final List<AnnotationAttributes> annotationAttributes = new ArrayList<>(maps.size()); for (final Map<String, Object> map : maps) { annotationAttributes.add(AnnotationAttributes.fromMap(map)); } return annotationAttributes; } private ConditionOutcome determineOutcome(AnnotationAttributes annotationAttributes, PropertyResolver resolver) { final Spec spec = new Spec(annotationAttributes); final List<String> missingProperties = new ArrayList<>(); final List<String> nonMatchingProperties = new ArrayList<>(); spec.collectProperties(resolver, missingProperties, nonMatchingProperties); // 1)屬性值不存在 if (!missingProperties.isEmpty()) { return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnProperty.class, spec) .didNotFind("property", "properties").items(Style.QUOTE, missingProperties)); } // 2)屬性值存在,可是不匹配 if (!nonMatchingProperties.isEmpty()) { return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnProperty.class, spec) .found("different value in property", "different value in properties") .items(Style.QUOTE, nonMatchingProperties)); } // 此 ConditionalOnProperty 條件匹配 return ConditionOutcome .match(ConditionMessage.forCondition(ConditionalOnProperty.class, spec).because("matched")); } private static class Spec { private final String prefix; private final String havingValue; private final String[] names; private final boolean matchIfMissing; Spec(AnnotationAttributes annotationAttributes) { // 讀取 ConditionalOnProperty 註解的 prefix 屬性 String prefix = annotationAttributes.getString("prefix").trim(); // prefix 不爲空,則嘗試添加 . 後綴 if (StringUtils.hasText(prefix) && !prefix.endsWith(".")) { prefix = prefix + "."; } this.prefix = prefix; // 讀取 ConditionalOnProperty 註解的 havingValue 屬性 havingValue = annotationAttributes.getString("havingValue"); // 讀取 ConditionalOnProperty 註解的關聯屬性名稱 names = getNames(annotationAttributes); // 讀取 ConditionalOnProperty 註解的 matchIfMissing 屬性 matchIfMissing = annotationAttributes.getBoolean("matchIfMissing"); } private String[] getNames(Map<String, Object> annotationAttributes) { final String[] value = (String[]) annotationAttributes.get("value"); final String[] name = (String[]) annotationAttributes.get("name"); Assert.state(value.length > 0 || name.length > 0, "The name or value attribute of @ConditionalOnProperty must be specified"); Assert.state(value.length == 0 || name.length == 0, "The name and value attributes of @ConditionalOnProperty are exclusive"); // value 屬性的優先級高於 name return value.length > 0 ? value : name; } private void collectProperties(PropertyResolver resolver, List<String> missing, List<String> nonMatching) { // 遍歷全部的屬性名稱 for (final String name : names) { // 添加前綴 final String key = prefix + name; // 1)若是 Environment 中存在此屬性 if (resolver.containsProperty(key)) { // 指定的值不匹配,則寫入 nonMatching 中 if (!isMatch(resolver.getProperty(key), havingValue)) { nonMatching.add(name); } // 2)Environment 中不存在此屬性 } else { // 若是不能忽略此屬性,則寫入 missing 中 if (!matchIfMissing) { missing.add(name); } } } } private boolean isMatch(String value, String requiredValue) { // 1)指定了必須的值,則使用 equals 進行比較 if (StringUtils.hasLength(requiredValue)) { return requiredValue.equalsIgnoreCase(value); } // 只要屬性值不是忽略大小寫的 false,就匹配 return !"false".equalsIgnoreCase(value); } @Override public String toString() { final StringBuilder result = new StringBuilder(); result.append("("); result.append(prefix); if (names.length == 1) { result.append(names[0]); } else { result.append("["); result.append(StringUtils.arrayToCommaDelimitedString(names)); result.append("]"); } if (StringUtils.hasLength(havingValue)) { result.append("=").append(havingValue); } result.append(")"); return result.toString(); } } }
ConfigurationClassBeanDefinitionReader.loadBeanDefinitions()方法的功能就是將以前解析出的configClasses配置類信息中全部配置相關的信息添加到spring的bean定義,主要是配置類中的@Bean註解方法,配置類@ImportResource和@Import(實現ImportBeanDefinitionRegistrar接口方式)的bean註冊
ConfigurationClassBeanDefinitionReader.loadBeanDefinitions()方法 實現邏輯以下:
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.removeImportingClass(configClass.getMetadata().getClassName()); return; } if (configClass.isImported()) { registerBeanDefinitionForImportedConfigurationClass(configClass); } //將@Bean方法註冊爲bean for (BeanMethod beanMethod : configClass.getBeanMethods()) { loadBeanDefinitionsForBeanMethod(beanMethod); } //將configClass中中ImportResource指定的資源註冊爲bean loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()); //將configClass中ImportedRegistrar註冊爲bean loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); }
處理邏輯理了一遍後,看一下ConfigurationClassPostProcessor處理器解析@configuration配置類主要過程:
1. Spring容器初始化時註冊默認後置處理器ConfigurationClassPostProcessor
2. Spring容器初始化執行refresh()方法中調用ConfigurationClassPostProcessor
3. ConfigurationClassPostProcessor處理器藉助ConfigurationClassParser完成配置類解析
4. ConfigurationClassParser配置內解析過程當中完成嵌套的MemberClass、@PropertySource註解、@ComponentScan註解(掃描package下的全部Class並進行迭代解析,主要是@Component組件解析及註冊)、@ImportResource、@Bean等處理
5. 完成@Bean註冊, @ImportResource指定bean的註冊以及@Import(實現ImportBeanDefinitionRegistrar接口方式)的bean註冊
掃描Bean的順序(並非Bean定義真正註冊的順序):
@Import:相對複雜點,以下:
由上可見,這九步中,惟獨只有@ComponentScan掃描到的Bean這個時候的Bean定義信息是已經註冊上去了的,其他的都尚未真正註冊到註冊中心。
注意:bean註冊的前後順序,將直接影響到Bean的覆蓋(默認Map,後註冊的覆蓋先註冊的,固然還和scope有關)