日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

@param注解的用法解析_SpringBoot 配置类解析

發(fā)布時(shí)間:2025/3/15 javascript 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 @param注解的用法解析_SpringBoot 配置类解析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

本文首發(fā)于 vivo互聯(lián)網(wǎng)技術(shù) 微信公眾號
鏈接:https://mp.weixin.qq.com/s/NvPO5-FWLiOlrsOf4wLaJA
作者:Li Wanghong

SpringBoot作為Java領(lǐng)域非常流行的開源框架,集成了大量常用的第三方庫配置,Spring Boot應(yīng)用中這些第三方庫幾乎可以是零配置的開箱即用,大部分的 Spring Boot 應(yīng)用都只需要非常少量的配置代碼,開發(fā)者能夠更加專注于業(yè)務(wù)邏輯。SpringBoot上手快,但是如果你的項(xiàng)目中業(yè)務(wù)場景需要一些特殊定制,甚至對源碼進(jìn)行定制化,那這時(shí)候了解原理就變成必需的了,只有充分了解源碼,知道框架底層的工作原理,才能對源碼中原有的機(jī)制進(jìn)行修改 / 擴(kuò)展等等。本文介紹了SpringBoot如何解析配置類、如何集成第三方配置。

一、基本概念介紹

在SpringBoot中推薦基于Java Config的方式來代替?zhèn)鹘y(tǒng)的XML方式去引入Bean,本文就是分析SpringBoot如何解析這些配置類,為容器中注入我們自定義的以及SpringBoot為我們提供的Bean。SpringBoot版本基于2.1.7.RELEASE。

// 通常一個SpringBoot工程會含有這樣一個主配置類,它位于我們項(xiàng)目的根包下,通過啟動這個main方法就可以啟動我們的項(xiàng)目 // 下面我們先分析@SpringBootApplication注解有哪些作用,在第二節(jié)中分析run方法,在run方法中會進(jìn)行配置類的解析 @SpringBootApplication public class SpringbootApplication {public static void main(String[] args) {SpringApplication.run(SpringbootApplication.class, args);} }// 點(diǎn)擊@SpringBootApplication進(jìn)去發(fā)現(xiàn)它其實(shí)是由三個核心注解構(gòu)成的,下面分別講解這三個注解 @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication {

1、@SpringBootConfiguration注解

// 點(diǎn)進(jìn)去發(fā)現(xiàn)它其實(shí)就是一個@Configuration注解,SpringBoot解析到就會知道這是一個配置類,會給容器中引入一些bean // 一個被@Configuration標(biāo)注的類,相當(dāng)于一個applicationContext.xml文件 // @Configuration點(diǎn)進(jìn)去發(fā)現(xiàn)其實(shí)就是一個@Component注解 @Configuration public @interface SpringBootConfiguration {}

2、@EnableAutoConfiguration注解

// 結(jié)合下面@AutoConfigurationPackage注解,發(fā)現(xiàn)@EnableAutoConfiguration注解就是通過@Import注解給容器中引入了兩個bean, // 分別是AutoConfigurationImportSelector和AutoConfigurationPackages.Registrar,通過這兩個類可以給容器中引入更多的類 // 下面先介紹下@Import注解的使用 @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { }@Import(AutoConfigurationPackages.Registrar.class) public @interface AutoConfigurationPackage { }

@Import注解

在原生SpringFramework中,裝配組件有下面三種方式

  • 使用@Component注解,Spring2.5+
  • 使用配置類@Configuration與@Bean,Spring3.0+
  • 使用模塊裝配@EnableXXX與@Import,Spring3.1+
  • 如果要注冊較多的Bean,通過1) 2) 兩種方式不太方便,可以通過Spring提供的模塊裝配功能,通過給配置類標(biāo)注@Enable注解,再在注解上標(biāo)注@Import注解,即可完成組件裝配的效果,下面通過一個例子講解@EnableXXX和@Import的使用。

    // 步驟1) // 創(chuàng)建幾個動物的實(shí)體類,如Cat、Bird、Chicken、Dog、Duck、Pig、Sheep、Snake、Tiger // 接下來會通過@Import的各種用法將這些bean注入到容器中 @Data public class Cat {private String name; }// 步驟2) 在主配置類上加上我們自定義的@EnableAnimal注解,含義就是通過@EnableAnimal會給容器中導(dǎo)入上述的那些動物Bean // @EnableAnimal就可以類比我們上面說的@EnableAutoConfiguration注解,兩者功能類似 @SpringBootApplication @EnableAnimal public class SpringbootApplication {public static void main(String[] args) {SpringApplication.run(SpringbootApplication.class, args);} }// 步驟3) // @EnableAnimal如下所示,這是我們自定義的注解,這個注解的核心是是在上面聲明了@Import注解 // @Import注解可以傳入四種類型,普通類、配置類、ImportSelector的實(shí)現(xiàn)類、ImportBeanDefinitionRegistar的實(shí)現(xiàn)類 // 下面分別講解@Import注解導(dǎo)入四種類型的用法 @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Import({Dog.class, AnimalRegisterConfiguration.class, AnimalImportSelector.class, AnimalImportBeanDefinitionRegistar.class}) public @interface EnableAnimal { }// 1) 直接@Import({Dog.class}),則容器啟動完成之后容器中就有Dog這個bean,注意Dog這個類我們并沒有通過@Component方式注入// 2) @Import ({AnimalRegisterConfiguration.class}),通過這種Import配置類形式也可以導(dǎo)入@Configuration public class AnimalRegisterConfiguration {@Beanpublic Cat cat(){return new Cat("cat");} }// 3) @Import({AnimalImportSelector.class}),通過返回一個Spring數(shù)組的方式,數(shù)組中可以方便的指定多個Bean // 我們上面說的AutoConfigurationImportSelector就是這種方式,SpringBoot給容器中導(dǎo)入MybatisAutoConfiguration // 等自動配置類就是通過這種方式導(dǎo)入的,第二節(jié)配置類解析會講這個 public class AnimalImportSelector implements ImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {return new String[] {Tiger.class.getName()};} }// 4) @Import({AnimalImportBeanDefinitionRegistar.class}),通過手動編碼方式向registry注入Bean // 我們上面說的AutoConfigurationPackages.Registrar就是這種方式public class AnimalImportBeanDefinitionRegistar implements ImportBeanDefinitionRegistrar {@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {registry.registerBeanDefinition("snake", new RootBeanDefinition(Snake.class));} }

    3、@ComponentScan注解

    這個注解就是相當(dāng)于XML中的<context:component-scan>,它會從定義的掃描包路徑(默認(rèn)是SpringBoot主配置所在的包及其子包)掃描標(biāo)識了@Controller、@Service、@Repository、@Component注解的類到Spring容器中。

    // 我們可以看到這個@ComponentScan注解上顯示指定了兩個Filter過濾條件,它是SpringBoot提供的一種擴(kuò)展機(jī)制,能讓我們 // 向IOC容器中注冊一些自定義的組件過濾器,以便在包掃描的過程中過濾一些Bean @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })// 這是TypeExcludeFilter的方法,可以看到它是獲取容器中所有的TypeExcludeFilter,并遍歷它們?nèi)ミ^濾一些不想要的Bean public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {if (this.beanFactory instanceof ListableBeanFactory && getClass() == TypeExcludeFilter.class) {Collection<typeexcludefilter> delegates= ((ListableBeanFactory) this.beanFactory).getBeansOfType(TypeExcludeFilter.class).values();for (TypeExcludeFilter delegate : delegates) {if (delegate.match(metadataReader, metadataReaderFactory)) {return true;}}}return false; }// 我們可以自定義一個TypeExcludeFilter,它的功能就是過濾掉User這個bean,不讓它注入到容器中 @Component public class MyTypeExcludeFilter extends TypeExcludeFilter {@Overridepublic boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {return User.class.getName().equals(metadataReader.getClassMetadata().getClassName());} }@Component public class User {private String name; }// 可以看到AutoConfigurationExcludeFilter就是將自動配置類給過濾掉了,因?yàn)樽詣优渲妙恱xxAutoConfiguration是通過 // 上面說的AutoConfigurationImportSelector方式導(dǎo)入的,沒必要導(dǎo)入兩次 public class AutoConfigurationExcludeFilter implements TypeFilter, BeanClassLoaderAware {public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {return isConfiguration(metadataReader) && isAutoConfiguration(metadataReader);} }

    4、@Conditional注解

    我們說SpringBoot約定大于配置,它通過一些xxxAutoConfiguration給容器中導(dǎo)入了一些組件,如果你需要但是沒有配置視圖解析器,則SpringBoot就會提供其默認(rèn)配置的視圖解析器,這樣就簡化了配置。那么如果自己定義了一個視圖解析器,那么到底SpringBoot會往容器中注入哪個呢? 查看下面默認(rèn)注入的視圖解析器代碼,發(fā)現(xiàn)其上面有一個@ConditionalOnMissingBean注解,意思就是若容器中沒有這個則容器會給你注入一個這樣的視圖解析器,若容器中有就不注入了。

    // @ConditionalOnMissingBean是通過@Conditional注解和Condition接口的實(shí)現(xiàn)類(OnBeanCondition.class)來實(shí)現(xiàn)這個效果的 @Bean @ConditionalOnMissingBean public InternalResourceViewResolver defaultViewResolver() {@Conditional(OnBeanCondition.class) public @interface ConditionalOnMissingBean {@FunctionalInterface public interface Condition {boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata); }

    我們也可以自己實(shí)現(xiàn)一個自定義的條件注解。

    // 自定義一個Condition接口的實(shí)現(xiàn)類MyCondition,通過其matches方法來判斷是否符合指定條件 public class MyCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {// 獲取注解MyConditionAnotation注解上指定value對應(yīng)的值,如果沒有這個值,則不符合條件String[] value = (String[]) metadata.getAnnotationAttributes(MyConditionAnotation.class.getName()).get("value");for (String property : value){if(StringUtils.isEmpty(context.getEnvironment().getProperty(property))){return false;}}return true;} }@Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.TYPE, ElementType.METHOD }) @Documented @Conditional(MyCondition.class) public @interface MyConditionAnotation {String[] value() default {}; }// 通過@Component給容器中注入一個A類型Bean,條件是@MyConditionAnotation注解指定的key1、key2對應(yīng)的值有配置 @Component @MyConditionAnotation({"key1", "key2"}) public class A { }

    5、SpringFactoriesLoader

    類似Java的SPI、Dubbo的SPI機(jī)制,SpringBoot也提供了一種機(jī)制,它通過讀取META-INF/spring.factories文件(這些文件可能存在于類路徑中的多個jar包中)來加載一些預(yù)先配置的類,而這個核心機(jī)制來源于SpringFactoriesLoader。spring.factories文件必須采用 properties 格式,其中key是接口或抽象類的全限定名,而value是用逗號分隔的實(shí)現(xiàn)類的全限定類名列表。

    // 我們先來看下上面講解@Import注解講到的AutoConfigurationImportSelector,我們說通過它就可以導(dǎo)入SpringBoot提供那些 // 自動配置類. 下面是Import注解講到的AutoConfigurationImportSelector的selectImport方法 @Override public String[] selectImports(AnnotationMetadata annotationMetadata) {// 忽略一些其他代碼// 這里的含義就是通過SpringFactoriesLoader去加載META-INF/spring.factories中配置的那些xxxAutoConfiguration// 并放入String數(shù)組返回AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); }// 忽略中間過程調(diào)用,后面會分析,接下來就走到這里通過SpringFactoriesLoader去加載自動配置類 protected List<string> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {// 具體調(diào)用看下面分析List<string> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());return configurations; }protected Class<?> getSpringFactoriesLoaderFactoryClass() {return EnableAutoConfiguration.class; }public static List<string> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {// org.springframework.boot.autoconfigure.EnableAutoConfigurationString factoryClassName = factoryClass.getName();// 獲得一個Map,map形如<key,List<String>&gt;形式,后面getOrDefault是獲取// org.springframework.boot.autoconfigure.EnableAutoConfiguration對應(yīng)的實(shí)現(xiàn)類集合// 注意這里面不僅僅是加載自動配置類,也會加載監(jiān)聽器、初始化器那些容器配置的實(shí)現(xiàn)類,這里統(tǒng)一一次加載之后放到緩存中return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList()); }// 帶緩存功能,從各個jar包的META-INF/spring.factories文件中加載實(shí)現(xiàn)類,一個key可能包含多個實(shí)現(xiàn) private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {MultiValueMap<String, String> result = cache.get(classLoader);if (result != null) {// 緩存中有直接返回return result;}try {// FACTORIES_RESOURCE_LOCATION值是META-INF/spring.factoriesEnumeration<url> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));result = new LinkedMultiValueMap<>();while (urls.hasMoreElements()) {URL url = urls.nextElement();UrlResource resource = new UrlResource(url);Properties properties = PropertiesLoaderUtils.loadProperties(resource);for (Map.Entry<?, ?> entry : properties.entrySet()) {// 獲取keyString factoryClassName = ((String) entry.getKey()).trim();// 將value逗號分隔,獲得各個具體的實(shí)現(xiàn)類for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {// 放入result中result.add(factoryClassName, factoryName.trim());}}}cache.put(classLoader, result);// 返回的result見下圖return result;} }

    可以看到返回了很多自動配置類,有AopAutoConfiguration、RabbitAutoConfiguration,也有MybatisAutoConfiguraion等(圖中沒有截全)

    6、BeanFactoryPostProcessor

  • BeanFactoryPostProcessor,BeanFactory后置處理器,是針對于BeanFactory的擴(kuò)展點(diǎn),即Spring會在BeanFactory初始化之后,beanDefinition都已經(jīng)loaded,但是bean還未創(chuàng)建前進(jìn)行調(diào)用,可以修改或增加BeanDefinition。
  • BeanDefinitionRegistryPostProcessor,是BeanFactoryPostProcessor的子接口,是針對于BeanFactory的擴(kuò)展點(diǎn),即Spring會在調(diào)用BeanFactoryPostProcessor之前調(diào)用它。我們下面要重點(diǎn)分析的
  • ConfigurationClassPostProcessor就是該接口的實(shí)現(xiàn)類,SpringBoot就是通過它去解析配置類,封裝成一個個BeanDefinition注入到容器中。
  • BeanPostProcessor,是針對Bean的擴(kuò)展點(diǎn),即Spring會在Bean初始化前后調(diào)用方法對Bean進(jìn)行處理,AOP、依賴注入就是通過BeanPostProcessor實(shí)現(xiàn)的。
  • 下面是自定義的一個BeanFactoryPostProcessor和BeanPostProcessor,發(fā)現(xiàn)通過BeanFactoryPostProcessor可以往容器中增加新的Bean或者修改原有的Bean定義,通過BeanPostProcessor可以修改已經(jīng)創(chuàng)建好的Bean的屬性值。

    @Component public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;// 往容器中新增BeanDefinitionGenericBeanDefinition beanDefinition = new GenericBeanDefinition();beanDefinition.setBeanClass(Chicken.class);registry.registerBeanDefinition("beanFactoryPostProcessor-Chicken", beanDefinition);// 修改容器中原有的BeanDefinitionBeanDefinition snake = registry.getBeanDefinition("snake");snake.setLazyInit(true);} }@Component public class CatBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof Cat){Cat cat = (Cat) bean;cat.setName("changeNameCat");}return bean;} }

    二、SpringBoot啟動流程概述

    第一節(jié)是SpringBoot解析自動配置類會用到的一些知識點(diǎn),下面我們來看SpringBoot解析配置類的具體過程。上圖是SpringBoot啟動流程圖,其中在refreshContext的第五步會調(diào)用容器的BeanFactoryPostProcessor的postProcessBeanDefinitionRegistry方法。其中有一個是ConfigurationClassPostProcessor,它是在創(chuàng)建ConfigurableApplicationContext時(shí)設(shè)置到容器中的,如下所示。

    // 圖中說的創(chuàng)建ConfigurableApplicationContext,默認(rèn)創(chuàng)建的是普通的Servlet Web容器,就是下面這個 // 通過反射創(chuàng)建會走到其默認(rèn)的構(gòu)造函數(shù) public AnnotationConfigServletWebServerApplicationContext() {// 這里面進(jìn)去會走到下面代碼this.reader = new AnnotatedBeanDefinitionReader(this);this.scanner = new ClassPathBeanDefinitionScanner(this); }// 走到這里 registerAnnotationConfigProcessors(registry, null);// 走到這里 // 向容器中注入一個ConfigurationClassPostProcessor,它是BeanFactoryPostProcessor if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)); }// 向容器中注入一個AutowiredAnnotationBeanPostProcessor,它是BeanPostProcessor,用于解決依賴注入的 if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); }

    三、配置類解析

    上面說到在refreshContex中的第五步時(shí),會調(diào)用容器中的BeanFactoryPostProcessor

    的postProcessBeanDefinitionRegistry方法。其中有一個是ConfigurationClassPostProcessor,這是我們解析自動配置類的入口,下面分析其postProcessBeanDefinitionRegistry方法。

    1、配置類解析流程概述

    @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { // 刪掉一些非關(guān)鍵代碼processConfigBeanDefinitions(registry); }

    下面的processConfigBeanDefinitions方法就是對應(yīng)上圖中的步驟1、2、3、4、5,其中步驟4和步驟5比較長,單獨(dú)拆出來分析。

    public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { List<beandefinitionholder> configCandidates = new ArrayList<>(); // 獲取容器中已注冊的bean名字,見下圖,注意,這里容器中這些BeanDefinition都是容器初始化過程中容器添加進(jìn)去的// 不是我們業(yè)務(wù)代碼的beanDefinition,這段代碼其實(shí)是連貫的,為了注釋圖片方便才分開String[] candidateNames = registry.getBeanDefinitionNames(); for (String beanName : candidateNames) { // 獲取BeanDefinitionBeanDefinition beanDef = registry.getBeanDefinition(beanName); // 判斷這個BeanDefinition的configurationClass屬性是不是full或者lite,如果是認(rèn)為已經(jīng)處理過了,第一次時(shí)默認(rèn)為空,// 走下面分支if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) || ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) { // 打印日志記錄下} else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {// 1) 下面先分析下這個checkConfigurationClassCandidate方法,這邊看方法名也可以猜到是檢測該類是不是配置類// 是配置類的意思就是它會給容器中引入bean,這個方法判斷主要就是看這個類的元信息中有沒有@Configuration注解// 有沒有@Component注解、有沒有@ComponentScan、@Import、@ImportResource注解,有沒有@Bean方法// 構(gòu)造一個BeanDefinitionHolder,放入configCandidates中configCandidates.add(new BeanDefinitionHolder(beanDef, beanName)); } } // Return immediately if no @Configuration classes were found // 上圖中容易默認(rèn)已經(jīng)引入了7個BeanDefinition,經(jīng)過上面檢測發(fā)現(xiàn)默認(rèn)就一個符合條件的配置類,即我們的主配置類// 這里面configCandidates就一個,就是SpringBootApplicationif (configCandidates.isEmpty()) { return; } // Sort by previously determined @Order value, if applicable // 排序configCandidates.sort((bd1, bd2) -> { int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition()); int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition()); return Integer.compare(i1, i2); }); // 刪掉部分代碼// Parse each @Configuration class // 配置類解析工具ConfigurationClassParser parser = new ConfigurationClassParser( this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, this.componentScanBeanNameGenerator, registry); // 待處理集合Set<beandefinitionholder> candidates = new LinkedHashSet<>(configCandidates); // 已處理集合Set<configurationclass> alreadyParsed = new HashSet<>(configCandidates.size()); // 循環(huán)處理直到candidates.isEmpty()do { // 這邊開始解析,對應(yīng)步驟4parser.parse(candidates); parser.validate(); // 取出第四步解析得到的一些configurationClasses集合Set<configurationclass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses()); configClasses.removeAll(alreadyParsed); // 刪除一部分代碼// 這邊也會去加載BeanDefinition,對應(yīng)圖中步驟五this.reader.loadBeanDefinitions(configClasses); alreadyParsed.addAll(configClasses); } while (!candidates.isEmpty()); }

    2、檢測是否是配置類

    在配置類解析流程圖中,第二步,會獲取容器中已經(jīng)注冊的BeanDefinition,放入candidateNames中,然后依次遍歷這些BeanDefinition,判斷它有沒有被處理過,如果處理過就不管,否則通過checkConfigurationClassCandidate方法去判斷它是不是配置類,判斷方法如下。通過閱讀這段代碼,發(fā)現(xiàn)如果一個類上面有@Configuration注解、或者有@Component、@ComponentScan、@Import、@ImportResource注解、或者有@Bean標(biāo)注的方法,則認(rèn)為它是一個配置類。默認(rèn)情況下,走到這里時(shí)最終只有一個candidateName符合,它是我們的主配置類,也就是SpringbootApplication這個Bean。

    ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory);public static boolean checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) { String className = beanDef.getBeanClassName(); // 獲取下類名,如果類名為空或者該類為工廠類if (className == null || beanDef.getFactoryMethodName() != null) { return false; } // 獲取類的元數(shù)據(jù)信息AnnotationMetadata metadata; // 上圖的7個candidateNames中只有一個springbootApplication是AnnotatedBeanDefinition,其余全返回falseif (beanDef instanceof AnnotatedBeanDefinition &&className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) { // Can reuse the pre-parsed metadata from the given BeanDefinition... // springbootApplication走到這里metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata(); } else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) { // Check already loaded Class if present... // since we possibly can't even load the class file for this Class. Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass(); metadata = new StandardAnnotationMetadata(beanClass, true); } else { try { MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className); // 讀取類的元數(shù)據(jù)信息,這里面包括注解等信息metadata = metadataReader.getAnnotationMetadata(); } catch (IOException ex) { return false; } } // metadata.isAnnotated(Configuration.class.getName()),這個就是判斷類上面有沒有@Configuration注解if (isFullConfigurationCandidate(metadata)) { // 如果true的話設(shè)置下這個屬性,那么就標(biāo)記為處理過了beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL); } else if (isLiteConfigurationCandidate(metadata)) { beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE); } else { // 其余6個返回falsereturn false; } // It's a full or lite configuration candidate... Let's determine the order value, if any. Integer order = getOrder(metadata); if (order != null) { // 獲取下類上的@Order信息beanDef.setAttribute(ORDER_ATTRIBUTE, order); } return true; }public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata) { // Do not consider an interface or an annotation... if (metadata.isInterface()) { return false; } // Any of the typical annotations found? for (String indicator : candidateIndicators) { // 判斷下類上面有沒有這幾個注解if (metadata.isAnnotated(indicator)) { return true; } } // Finally, let's look for @Bean methods... try { // 判斷有沒有@Bean的方法return metadata.hasAnnotatedMethods(Bean.class.getName()); } return false; } }private static final Set<string> candidateIndicators = new HashSet<>(); static { candidateIndicators.add(Component.class.getName()); candidateIndicators.add(ComponentScan.class.getName()); candidateIndicators.add(Import.class.getName()); candidateIndicators.add(ImportResource.class.getName()); }

    3、步驟四解析

    public void parse(Set<beandefinitionholder> configCandidates) { // 刪除部分代碼,實(shí)際執(zhí)行時(shí)這里的configCandidates就一個springBootApplication代表的主配置類for (BeanDefinitionHolder holder : configCandidates) {// 獲取BeanDefinitionBeanDefinition bd = holder.getBeanDefinition(); // 我們的SpringBootApplication會走到這邊,下面先分析這邊parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName()); } // (**)處這邊也要留意下,這邊會處理DeferredImportSelector,我們前面說的AutoConfigurationImportSelector就是在這邊處理// 給容器中導(dǎo)入xxxAutoConfigurationthis.deferredImportSelectorHandler.process(); }protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException { processConfigurationClass(new ConfigurationClass(metadata, beanName)); }protected void processConfigurationClass(ConfigurationClass configClass) throws IOException { // 根據(jù)當(dāng)前類上面的@Conditional注解標(biāo)注的條件判斷是否要解析這個配置類if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) { return; } // 以configClass作為key去獲取,第一次來肯定是獲取不到的,走下面邏輯ConfigurationClass existingClass = this.configurationClasses.get(configClass); if (existingClass != null) { if (configClass.isImported()) { if (existingClass.isImported()) { existingClass.mergeImportedBy(configClass); } // Otherwise ignore new imported config class; existing non-imported class overrides it. return; } else { // Explicit bean definition found, probably replacing an import. // Let's remove the old one and go with the new one. this.configurationClasses.remove(configClass); this.knownSuperclasses.values().removeIf(configClass::equals); } } // Recursively process the configuration class and its superclass hierarchy.// 這一步其實(shí)沒有做啥,重點(diǎn)還是看下一步驟SourceClass sourceClass = asSourceClass(configClass); do { // 這里是重點(diǎn),里面具體分為8大步驟,單獨(dú)拿一小節(jié)分析// b) doProcessConfigurationClasssourceClass = doProcessConfigurationClass(configClass, sourceClass); } while (sourceClass != null); // 放入configurationClasses中this.configurationClasses.put(configClass, configClass); }// 上面的asSourceClass最終其實(shí)就是封裝了一個SourceClass對象 public SourceClass(Object source) { this.source = source; if (source instanceof Class) { this.metadata = new StandardAnnotationMetadata((Class<?>) source, true); } else { this.metadata = ((MetadataReader) source).getAnnotationMetadata(); } }

    下面這個doProcessConfigurationClass具體分為8個小步驟去解析,對應(yīng)步驟四種的A-H步驟

    protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { // 判斷這個類上面有沒有@Component注解 if (configClass.getMetadata().isAnnotated(Component.class.getName())) { // Recursively process any member (nested) classes first // 如果有的話,遍歷其內(nèi)部類,然后也是調(diào)用doProcessConfigurationClass遞歸處理processMemberClasses(configClass, sourceClass); } // Process any @PropertySource annotations// 處理PropertySource注解,之前講解屬性配置也分析過,就是將該注解對應(yīng)的屬性文件加載到Environment中for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), PropertySources.class, org.springframework.context.annotation.PropertySource.class)) { if (this.environment instanceof ConfigurableEnvironment) { processPropertySource(propertySource); } } // Process any @ComponentScan annotations // 處理@ComponentScan注解,將其指定的包下的bean注冊到框架中Set<annotationattributes> componentScans = AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class); if (!componentScans.isEmpty() &&!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) { for (AnnotationAttributes componentScan : componentScans) { // The config class is annotated with @ComponentScan -&gt; perform the scan immediately Set<beandefinitionholder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()); // Check the set of scanned definitions for any further config classes and parse recursively if needed for (BeanDefinitionHolder holder : scannedBeanDefinitions) { BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition(); if (bdCand == null) { bdCand = holder.getBeanDefinition(); } if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) { parse(bdCand.getBeanClassName(), holder.getBeanName()); } } } } // Process any @Import annotations // 處理Import注解processImports(configClass, sourceClass, getImports(sourceClass), true); // Process any @ImportResource annotations // 處理@ImportResource注解,可以通過它來指定xml文件,BeanFactory就會讀取這個xml文件將bean注冊進(jìn)去AnnotationAttributes importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class); if (importResource != null) { String[] resources = importResource.getStringArray("locations"); Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader"); for (String resource : resources) { String resolvedResource = this.environment.resolveRequiredPlaceholders(resource); configClass.addImportedResource(resolvedResource, readerClass); } } // Process individual @Bean methods // 處理我們的類中使用@Bean注解的方法,添加到configClass的beanMethod中Set<methodmetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass); for (MethodMetadata methodMetadata : beanMethods) { configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); } // Process default methods on interfaces // 處理接口的默認(rèn)方法,遍歷這個類的接口,判斷有沒有使用@Bean注解的非抽象方法,添加到configClass的beanMethod中processInterfaces(configClass, sourceClass); // Process superclass, if any // 遞歸處理父類,這邊返回父類上層方法會遞歸處理if (sourceClass.getMetadata().hasSuperClass()) { // 判斷父類不為null且不在knownSuperclasses中且不以Java開頭String superclass = sourceClass.getMetadata().getSuperClassName(); if (superclass != null && !superclass.startsWith("java") &&!this.knownSuperclasses.containsKey(superclass)) { this.knownSuperclasses.put(superclass, configClass); // Superclass found, return its annotation metadata and recurse return sourceClass.getSuperClass(); } } // No superclass -&gt; processing is complete return null; }

    (1)處理內(nèi)部類

    if (configClass.getMetadata().isAnnotated(Component.class.getName())) { // Recursively process any member (nested) classes first processMemberClasses(configClass, sourceClass); }// Register member (nested) classes that happen to be configuration classes themselves.private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { Collection<SourceClass> memberClasses = sourceClass.getMemberClasses(); // 判斷是否有內(nèi)部類,沒有的話直接不處理if (!memberClasses.isEmpty()) { List<SourceClass> candidates = new ArrayList<>(memberClasses.size()); for (SourceClass memberClass : memberClasses) { // 判斷是否是配置類,判斷也很簡單,之前分析過,判斷類上面有沒有@Configuration注解、@Import、@ImportResource// @Component、@ComponentScan以及@Bean標(biāo)注的方法if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) && !memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) { // 加入到candidates中然后排個序candidates.add(memberClass); } } OrderComparator.sort(candidates); for (SourceClass candidate : candidates) { // 防止A引入防止A引入B,B引入Aif (this.importStack.contains(configClass)) { this.problemReporter.error(new CircularImportProblem(configClass, this.importStack)); } else { this.importStack.push(configClass); try { // 放入棧中并遍歷處理這些配置類,也是遞歸處理,調(diào)用之前的doProcessConfigurationClass處理這個配置類processConfigurationClass(candidate.asConfigClass(configClass)); } finally { this.importStack.pop(); } } } } }

    (2)處理@PropertySource注解

    @SpringBootApplication @PropertySource({"demo.properties"}) public class Springboot2Application {for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), PropertySources.class, org.springframework.context.annotation.PropertySource.class)) { if (this.environment instanceof ConfigurableEnvironment) { // 這邊就不進(jìn)去看了,主要是讀取@PropertySource注解指定的文件,將其封裝成一個屬性集放入到環(huán)境中processPropertySource(propertySource); } }

    (3)處理@ComponentScan注解

    Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class); if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) { for (AnnotationAttributes componentScan : componentScans) { // The config class is annotated with @ComponentScan -> perform the scan immediately // 下面先分析這個parse方法Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()); // Check the set of scanned definitions for any further config classes and parse recursively if needed for (BeanDefinitionHolder holder : scannedBeanDefinitions) { BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition(); if (bdCand == null) { bdCand = holder.getBeanDefinition(); } // 如果是配置類,再遞歸處理if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) { parse(bdCand.getBeanClassName(), holder.getBeanName()); } } } }public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) { ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry, componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader); Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator"); boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass); // 設(shè)置一個bean名字生成器,默認(rèn)就是使用org.springframework.beans.factory.support.BeanNameGeneratorscanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator : BeanUtils.instantiateClass(generatorClass)); // 就是默認(rèn)的ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy"); if (scopedProxyMode != ScopedProxyMode.DEFAULT) { scanner.setScopedProxyMode(scopedProxyMode); } else { Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver"); // 理解是元數(shù)據(jù)解析器scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass)); } // 設(shè)置下掃描的資源模式,是**/*.classscanner.setResourcePattern(componentScan.getString("resourcePattern")); // 添加IncludeFilter和ExcludeFilterfor (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) { for (TypeFilter typeFilter : typeFiltersFor(filter)) { scanner.addIncludeFilter(typeFilter); } } for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) { for (TypeFilter typeFilter : typeFiltersFor(filter)) { scanner.addExcludeFilter(typeFilter); } } // 設(shè)置是否懶加載boolean lazyInit = componentScan.getBoolean("lazyInit"); if (lazyInit) { scanner.getBeanDefinitionDefaults().setLazyInit(true); } // 解析掃描的包路徑加入到basePackages中Set<String> basePackages = new LinkedHashSet<>(); String[] basePackagesArray = componentScan.getStringArray("basePackages"); for (String pkg : basePackagesArray) { String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg), ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); Collections.addAll(basePackages, tokenized); } for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) { // 解析basePackageClasses所在的包并加入到basePackagesbasePackages.add(ClassUtils.getPackageName(clazz)); } // 如果是空的,將聲明該注解所在的類的包加入到basePackagesif (basePackages.isEmpty()) { // 通常我們的主配置類是沒有聲明包掃描的路徑的,所以這里會將主配置類所在的包加到這里面basePackages.add(ClassUtils.getPackageName(declaringClass)); } // 添加一個ExcludeFilter,跳過聲明該注解的類scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) { @Override protected boolean matchClassName(String className) { return declaringClass.equals(className); } }); return scanner.doScan(StringUtils.toStringArray(basePackages)); }protected Set<BeanDefinitionHolder> doScan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>(); // 遍歷所有的包路徑for (String basePackage : basePackages) { // 獲取該包下面所有符合條件的BeanDefinition,然后遍歷處理,下面會分析Set<BeanDefinition> candidates = findCandidateComponents(basePackage); for (BeanDefinition candidate : candidates) { ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate); candidate.setScope(scopeMetadata.getScopeName()); // 通過beanNameGenerator生成beanNameString beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);// 這兩個if判斷邏輯比較簡單,就是設(shè)置一些Lazy、DependsOn屬性if (candidate instanceof AbstractBeanDefinition) { postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); } if (candidate instanceof AnnotatedBeanDefinition) { AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); } // 這邊是檢查下有沒有之前定義過這個BeanDefinitionif (checkCandidate(beanName, candidate)) { BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); // 將該beanDefinition加入到集合中,并注冊到容器中beanDefinitions.add(definitionHolder); registerBeanDefinition(definitionHolder, this.registry); } } } return beanDefinitions; }private Set<BeanDefinition> scanCandidateComponents(String basePackage) { Set<BeanDefinition> candidates = new LinkedHashSet<>(); try { // 掃描指定包路徑及其子包下面的class文件,將其封裝成Resource對象// classpath*:com/lwh/springboot/**/*.classString packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolveBasePackage(basePackage) + '/' + this.resourcePattern; Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath); for (Resource resource : resources) { if (resource.isReadable()) { try { MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource); if (isCandidateComponent(metadataReader)) { ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader); sbd.setResource(resource); sbd.setSource(resource); if (isCandidateComponent(sbd)) { candidates.add(sbd); } } } } }}return candidates; }// 通過之前設(shè)置的幾個filter進(jìn)行過濾 protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException { for (TypeFilter tf : this.excludeFilters) { if (tf.match(metadataReader, getMetadataReaderFactory())) { return false; } } for (TypeFilter tf : this.includeFilters) { if (tf.match(metadataReader, getMetadataReaderFactory())) { return isConditionMatch(metadataReader); } } return false; }

    (4)處理@Import注解

    // Process any @Import annotations // getImports方法就是去遞歸掃描configClass上面所有的注解,將@Import注解標(biāo)注的值放入importCandidates中,見下圖 processImports(configClass, sourceClass, getImports(sourceClass), true);private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, boolean checkForCircularImports) { if (importCandidates.isEmpty()) { return; } if (checkForCircularImports && isChainedImportOnStack(configClass)) { this.problemReporter.error(new CircularImportProblem(configClass, this.importStack)); } else { this.importStack.push(configClass); try { for (SourceClass candidate : importCandidates) { // 依次遍歷判斷類型// 其中有一個是這個類型,@Import(AutoConfigurationImportSelector.class)// 這個就是自動配置原理,導(dǎo)入xxxAutoConfiguration這些類if (candidate.isAssignable(ImportSelector.class)) { // Candidate class is an ImportSelector -> delegate to it to determine imports Class<?> candidateClass = candidate.loadClass(); // 實(shí)例化并調(diào)用xxxAware的方法并注入相關(guān)屬性ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class); ParserStrategyUtils.invokeAwareMethods( selector, this.environment, this.resourceLoader, this.registry); // 它是DeferredImportSelector類型的if (selector instanceof DeferredImportSelector) { // deferredImportSelectors = new ArrayList<>()// 這邊會將兩個參數(shù)封裝下加入到deferredImportSelectors中,后面處理// 加入到deferredImportSelectors中后,具體的處理是this.deferredImportSelectorHandler.process();this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector); } else { // 不是的話獲取@Import導(dǎo)入的類名數(shù)組String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames); // 然后再遞歸處理processImports(configClass, currentSourceClass, importSourceClasses, false); } } // @Import(AutoConfigurationPackages.Registrar.class),我們的主配置類上面的注解就是這個類型// 這個是用于導(dǎo)入主配置類所在包及其子包下的BeanDefinitionelse if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { // Candidate class is an ImportBeanDefinitionRegistrar -> // delegate to it to register additional bean definitions Class<?> candidateClass = candidate.loadClass(); ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class); ParserStrategyUtils.invokeAwareMethods( registrar, this.environment, this.resourceLoader, this.registry); // 這邊就是將這兩個參數(shù)作為key,value放入了一個map中// this.importBeanDefinitionRegistrars.put(registrar, importingClassMetadata);configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } else { // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> // process it as an @Configuration class this.importStack.registerImport( currentSourceClass.getMetadata(), candidate.getMetadata().getClassName()); // 當(dāng)做一個普通類處理,判斷是不是配置類,遞歸處理processConfigurationClass(candidate.asConfigClass(configClass)); } } } finally { this.importStack.pop(); } } }

    (5)處理@ImportSource注解

    // 這種就是Spring中常用的通過XML形式注入的方式 @SpringBootApplication @ImportResource("test.xml") public class Springboot2Application {// Process any @ImportResource annotations // 可以使用@ImportResource注解指定xml文件,導(dǎo)入BeanDefinition AnnotationAttributes importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class); if (importResource != null) { String[] resources = importResource.getStringArray("locations"); Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader"); for (String resource : resources) { // 就是test.xmlString resolvedResource = this.environment.resolveRequiredPlaceholders(resource); configClass.addImportedResource(resolvedResource, readerClass); } }public void addImportedResource(String importedResource, Class<? extends BeanDefinitionReader> readerClass) { // 這邊就是放入到了map中,這邊是先統(tǒng)一存放起來,在步驟五的4)在真正進(jìn)行導(dǎo)入BeanDefinitionthis.importedResources.put(importedResource, readerClass); }private final Map<String, Class<? extends BeanDefinitionReader>> importedResources = new LinkedHashMap<>();

    (6)處理@Bean標(biāo)注的方法

    // Process individual @Bean methods // 獲取當(dāng)前類中的Bean方法 Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass); for (MethodMetadata methodMetadata : beanMethods) { // 這邊也是加入到set中,見下面代碼,也是在步驟五的3)中進(jìn)行處理configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); }private final Set<BeanMethod> beanMethods = new LinkedHashSet<>();

    (7)處理默認(rèn)方法

    // 默認(rèn)方法舉例,主配置類實(shí)現(xiàn)這個接口就可以 public interface ConfigurationInterface {@Beandefault Pig pig(){return new Pig();} }// Process default methods on interfaces processInterfaces(configClass, sourceClass);// Register default methods on interfaces implemented by the configuration class.// 這邊也是遞歸處理其父接口,判斷父接口中默認(rèn)方法是不是@Bean方法private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { for (SourceClass ifc : sourceClass.getInterfaces()) { Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(ifc); for (MethodMetadata methodMetadata : beanMethods) { if (!methodMetadata.isAbstract()) { // 也是在步驟五的3)中進(jìn)行處理configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); } } processInterfaces(configClass, ifc); } }

    更多內(nèi)容請留意公眾號“vivo互聯(lián)網(wǎng)技術(shù)”

    總結(jié)

    以上是生活随笔為你收集整理的@param注解的用法解析_SpringBoot 配置类解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。