国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Spring Boot源碼解析 - 自動裝配原理

這篇具有很好參考價值的文章主要介紹了Spring Boot源碼解析 - 自動裝配原理。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

引言

Spring Boot自動裝配是Spring Boot框架的一個關(guān)鍵特性,它的目標是讓開發(fā)者能夠快速構(gòu)建Spring應用程序,減少繁瑣的配置工作。

?

一、注解解析

  • @SpringApplication

從啟動類@SpringApplication注解入手,@SpringBootApplication是一個組合注解,它是Spring Boot框架中常用的一個主要注解之一。它結(jié)合了多個注解,簡化了Spring Boot應用程序的配置。

@SpringBootApplication
public class MyApp {
    public static void main(String[] args) {
        SpringApplication.run(MyApp.class, args);
    }
}

?

@SpringBootApplication?包含以下三個核心注解:

  1. @SpringBootConfiguration:這是Spring Boot框架中的一個元注解,用于標識該類為Spring Boot的配置類。配置類是用來定義Bean和配置應用程序的類。
  2. @EnableAutoConfiguration:這個注解告訴Spring Boot根據(jù)類路徑下的依賴和配置自動配置Spring應用程序。它利用了Spring Boot的自動配置特性,根據(jù)條件化配置的原理,自動配置所需的Bean、組件和屬性。
  3. @ComponentScan:這個注解用于指定Spring Boot掃描組件的基礎(chǔ)包。Spring Boot會掃描這個包及其子包,查找?guī)в凶⒔猓ɡ?code>@Controller、@Service、@Repository、@Component等)的類,并將它們注冊為Spring管理的Bean。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration //標識為配置類
@EnableAutoConfiguration //開啟自動配置
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
      @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
    ...省略
}

EnableAutoConfiguration?是自動裝配的核心,下面我們對該注解展開分析。

  • @EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    ...省略
}

@EnableAutoConfiguration的源碼中,可以看到它使用@Import注解引入了AutoConfigurationImportSelector類。當Spring bean后置處理器掃描解析啟動類下所有包創(chuàng)建beanDefinition時,AutoConfigurationImportSelector會觸發(fā)自動裝配的加載過程。

  • @Import擴展點

@Import是一個用于導入其他配置類的擴展點。通過使用@Import注解,我們可以在一個配置類中引入其他的配置類,從而將它們的Bean定義和配置合并到當前配置中。

@Import導入配置類分為兩種:

  • 實現(xiàn)ImportSelector接口的類,執(zhí)行selectImports()返回一個字符串數(shù)組,其中包含要導入的配置類的全限定名。
  • 實現(xiàn)ImportBeanDefinitionRegistrar接口的類,執(zhí)行registerBeanDefinition()可以動態(tài)地注冊Bean定義,從而實現(xiàn)更復雜的配置。

Spring Boot源碼解析 - 自動裝配原理,java,spring boot,java

通過上述可知AutoConfigurationImportSelector??實現(xiàn)ImportSelector接口。該自動裝配核心類邏輯在接下的分析中展開說

二、spring boot 自動裝配原理分析

初始化SpringApplication
@SpringBootApplication
public class MyApp {
    public static void main(String[] args) {
        //第一步
        SpringApplication.run(MyApp.class, args);
    }
}

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
        //第二步
        return new SpringApplication(primarySources).run(args);
    }

//第三步
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        //資源加載器
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        //設(shè)置啟動引導類
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        //web應用類型:
        // 1. NONE  非web應用程序
        // 2. SERVLET web應用程序
        // 3. REACTIVE 響應式web引用程序
        //通過web應用類路徑選擇web應用類型
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        //Spring SPI機制獲取key為 ApplicationContextInitializer的類,并將它們作為應用程序上下文初始化器(ApplicationContextInitializer)注冊
        setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
        //Spring SPI機制獲取key為 ApplicationListener,并將它們作為應用程序事件監(jiān)聽器(ApplicationListener)注冊
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = deduceMainApplicationClass();
    }

這塊關(guān)注第一次調(diào)用Spring SPI機制的setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));

Spring SPI機制
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = getClassLoader();
        // Use names and ensure unique to protect against duplicates
        //Spring SPI機制加載 META-INF/spring.factories 文件以key,value形式的自動裝配類
        Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
    }

通過?SpringFactoriesLoader.loadFactoryNames(type, classLoader)?方法,從?META-INF/spring.factories?文件中加載指定接口類型的實現(xiàn)類的名稱集合,并將它們保存在一個?Set?中。

  • META-INF/spring.factories: 通常是用于自動裝配的配置文件,其包含了需要自動裝配的類的全限定名。

一些八股文認為在AutoConfigurationImportSelector使用Spring SPI加載META-INF/spring.factories獲取自動裝配類 ,其實不然,Spring SPI只加載一次META-INF/spring.factories,以key-value的形式進行本地緩存,后續(xù)觸發(fā)自動裝配時,從本地緩存中獲取自動裝配類集合

Spring Boot啟動的核心邏輯
public ConfigurableApplicationContext run(String... args) {
   .
   .省略
   .
   try {
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
      //初始化并配置應用程序的環(huán)境,包括加載配置文件、解析命令行參數(shù)、設(shè)置系統(tǒng)屬性等。
      ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
      configureIgnoreBeanInfo(environment);
       //打印Banner
      Banner printedBanner = printBanner(environment);
      //根據(jù)web類型創(chuàng)建ApplicationContext
      context = createApplicationContext();
       //SpringBootExceptionReporter用于報告Spring Boot應用程序啟動過程中的異常
      exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
            new Class[] { ConfigurableApplicationContext.class }, context);
      //準備ApplicationContext,包括設(shè)置環(huán)境、配置監(jiān)聽器、初始化Bean等操作。
      prepareContext(context, environment, listeners, applicationArguments, printedBanner);
      //這里會完成整個Spring IoC容器的初始化,包括解析Bean的定義,創(chuàng)建Bean實例,以及處理依賴注入等。
      refreshContext(context);
      .
      .省略
      .
   return context;
}

上述代碼中,除了createApplicationContext()refreshContext(context),其他部分與自動裝配無關(guān)。在后續(xù)的文章中,會進一步介紹這部分內(nèi)容。

createApplicationContext()做了什么?
protected ConfigurableApplicationContext createApplicationContext() {
        Class<?> contextClass = this.applicationContextClass;
        if (contextClass == null) {
            try {
                //根據(jù)webApplicationType枚舉類型,創(chuàng)建應用
                switch (this.webApplicationType) {
                case SERVLET: //SERVLET web應用程序
                    contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
                    break;
                case REACTIVE: //REACTIVE 響應式web引用程序
                    contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
                    break;
                default: //NONE  非web應用程序
                    contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
                }
            }
            catch (ClassNotFoundException ex) {
                throw new IllegalStateException(
                        "Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass",
                        ex);
            }
        }
        return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
    }

public AnnotationConfigServletWebServerApplicationContext() {
        //用于讀取基于注解的Bean定義的類
        this.reader = new AnnotatedBeanDefinitionReader(this);
        //用于掃描類路徑中的組件,并將其注冊為Spring管理的Bean定義。
        this.scanner = new ClassPathBeanDefinitionScanner(this);
}

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        Assert.notNull(environment, "Environment must not be null");
        this.registry = registry;
        this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
    //注冊BeanFactory后置處理器
    AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    }

//注冊BeanFactory后置處理器
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
            BeanDefinitionRegistry registry, @Nullable Object source) {
        .
        .省略
        .
        Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

        if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            //自動裝配重點:創(chuàng)建BeanFactory后置處理器 ConfigurationClassPostProcessor,用于掃描解析啟動類當前包以及子包下的配置類
            RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
            def.setSource(source);
            //注冊 ConfigurationClassPostProcessor
            beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
        }

        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));
        }

        // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
        if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            //創(chuàng)建BeanFactory后置處理器 CommonAnnotationBeanPostProcessor,處理依賴注入@Resource、WebServiceRef標注的字段以及方法
            RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
            def.setSource(source);
            //注冊CommonAnnotationBeanPostProcessor
            beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
        }
        .
        .省略
        .

        return beanDefs;
    }

上述這段代碼整體來說非常簡單,根據(jù) web應用類型創(chuàng)建ApplicationContext, 例如web應用類型為 SERVLET,創(chuàng)建AnnotationConfigServletWebServerApplicationContext。通過AnnotationConfigServletWebServerApplicationContext構(gòu)造方法創(chuàng)建?AnnotatedBeanDefinitionReader以及ClassPathBeanDefinitionScanner,我們需要注意的是AnnotatedBeanDefinitionReader涉及BeanFactory后置處理器注冊的內(nèi)容,可以看到這一步注冊了ConfigurationClassPostProcessor

  • AnnotatedBeanDefinitionReader: 用于讀取基于注解的Bean定義的類

  • ClassPathBeanDefinitionScanner: 用于掃描類路徑中的組件

  • ConfigurationClassPostProcessor?:? ? 用于掃描解析啟動類當前包以及子包下的配置類

refreshContext(context)做了什么?
@Override
    public void refresh() throws BeansException, IllegalStateException {
        ...省略

            /**
             * 共注冊了2個后置處理器
             * ApplicationContextAwareProcessor,用于執(zhí)行xxxAware接口中的方法
             * ApplicationListenerDetector,保證監(jiān)聽器被添加到容器中
             */
            prepareBeanFactory(beanFactory);
        try {

            //為容器的某些子類指定特殊的BeanPost事件處理器
            postProcessBeanFactory(beanFactory);

            //觸發(fā)BeanFactory后置處理器
            //定位注冊加載BeanDefinition, 能讓我們對容器中掃描出來的BeanDefinition做出修改以達到擴展的目的
            invokeBeanFactoryPostProcessors(beanFactory);

            //說白了就是beanFactory.addBeanPostProcessor(postProcessor);添加bean后置處理器
            registerBeanPostProcessors(beanFactory);

            初始化容器事件傳播器,添加事件傳播器到IOC容器
            initApplicationEventMulticaster();

            //啟動容器
            onRefresh();

            //為事件傳播器注冊事件監(jiān)聽器.
            registerListeners();

            //將解析的BeanDefinition注冊到IOC容器中
            finishBeanFactoryInitialization(beanFactory);

            //初始化容器的生命周期事件處理器,并發(fā)布容器的生命周期事
            finishRefresh();
        }
        ...省略
    }

refreshContext方法中,完成了整個Spring IoC容器的初始化,包括解析Bean的定義、創(chuàng)建Bean實例以及處理依賴注入等。我們主要關(guān)注invokeBeanFactoryPostProcessors(beanFactory)對配置類進行定位解析注冊BeanDefinition

invokeBeanFactoryPostProcessors(beanFactory)做了什么?

    protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        //遍歷內(nèi)部所有BeanDefinitionRegistry后置處理器 (繼承 BeanFactoryPostProcessor),
        //調(diào)用 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry 解析配置類成benaDefinition并注冊
        PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

        // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
        // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
        if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }
    }

    //第二步: 

invokeBeanFactoryPostProcessors方法中,會觸發(fā)所有BeanFactory后置處理器的執(zhí)行,其中ConfigurationClassPostProcessor后置處理器負責掃描解析啟動類當前包以及子包下的配置類,并將其注冊為Spring管理的BeanDefinition,接下來我們就看看它的源碼

ConfigurationClassPostProcessor源碼分析
    //調(diào)用 ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry 
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) 
        //獲取傳入的 BeanDefinitionRegistry 對象 registry 的哈希碼,作為標識
        int registryId = System.identityHashCode(registry);
        //通過檢查 registriesPostProcessed 集合和 factoriesPostProcessed 集合,防止了在同一個 BeanDefinitionRegistry 上重復執(zhí)行邏輯
        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);
        }
        this.registriesPostProcessed.add(registryId);

        //第三步
        processConfigBeanDefinitions(registry);
    }

    //處理一些自定義的BeanDefinition
    public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {

        //存放加了注解@Configuration @Component @ComponentScan @Import @ImportResource的類
        List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
        String[] candidateNames = registry.getBeanDefinitionNames();

        for (String beanName : candidateNames) {
            BeanDefinition beanDef = registry.getBeanDefinition(beanName);
            //判斷是否已經(jīng)處理
            if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
                    ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
                }
            } else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
                //存放加了注解@Configuration @Component @ComponentScan @Import @ImportResource的類
                configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
            }
        }

        ...省略

        // 創(chuàng)建配置類解析器,構(gòu)造方法會創(chuàng)建ComponentScanAnnotationParser掃描器
        // 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());
        do {
            //1.解析
            parser.parse(candidates);
            //驗證
            parser.validate();

            // 已經(jīng)解析過的配置類
            Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
            // 移除已經(jīng)解析過的配置類,防止重復加載了配置類中的bd
            configClasses.removeAll(alreadyParsed);

            // Read the model and create bean definitions based on its content
            if (this.reader == null) {
                this.reader = new ConfigurationClassBeanDefinitionReader(
                        registry, this.sourceExtractor, this.resourceLoader, this.environment,
                        this.importBeanNameGenerator, parser.getImportRegistry());
            }
            // 2. 將所有ConfigurationClass解析成BeanDefinition進行 @Condition... 匹配,然后注冊到beanDefinition容器中
            this.reader.loadBeanDefinitions(configClasses);
            alreadyParsed.addAll(configClasses);

            candidates.clear();
            // 如果大于,說明容器中新增了一些BeanDefinition,那么需要重新判斷新增的bd是否是配置類,如果是配置類,需要再次解析
            if (registry.getBeanDefinitionCount() > candidateNames.length) {
                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) {
                    if (!oldCandidateNames.contains(candidateName)) {
                        BeanDefinition bd = registry.getBeanDefinition(candidateName);
                        if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
                                !alreadyParsedClasses.contains(bd.getBeanClassName())) {
                            candidates.add(new BeanDefinitionHolder(bd, candidateName));
                        }
                    }
                }
                candidateNames = newCandidateNames;
            }
        }
        while (!candidates.isEmpty());

        // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
        // 注冊ImportRegistry到容器中
        // 當通過@Import注解導入一個全配置類A(被@Configuration注解修飾的類),A可以實現(xiàn)ImportAware接口
        // 通過這個Aware可以感知到是哪個類導入的
        if (sbr != null) {
            if (!sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
                sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
            }
        }

        if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
            // Clear cache in externally provided MetadataReaderFactory; this is a no-op
            // for a shared cache since it'll be cleared by the ApplicationContext.
            ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
        }
    }

//解析
public void parse(Set<BeanDefinitionHolder> configCandidates) {
   this.deferredImportSelectors = new LinkedList<>();

   // 在 new SpringApplication時候,會將 啟動類 生成為AnnotatedBeanDefinition,然后注入到beanDefinition容器中
   for (BeanDefinitionHolder holder : configCandidates) {
      BeanDefinition bd = holder.getBeanDefinition();
      try {
         if (bd instanceof AnnotatedBeanDefinition) {  
            //注解類解析方式
            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);
      }
   }

   //處理啟動類的自動裝配注解上@Import,對于 實現(xiàn)ImportSelector接口的執(zhí)行selectImport
   processDeferredImportSelectors();
}

private void processDeferredImportSelectors() {
        List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
        this.deferredImportSelectors = null;
        if (deferredImports == null) {
            return;
        }

        Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR);
        for (DeferredImportSelectorHolder deferredImport : deferredImports) {
            ConfigurationClass configClass = deferredImport.getConfigurationClass();
            try {
                // 獲取啟動類上的所有@Import的實現(xiàn)ImportSelector類,執(zhí)行selectImports
                // 自動裝配就在此處觸發(fā),獲取類處境
                String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());
                 // 處理selectImports返回的可導入自動裝配類
                //1. 實現(xiàn)imporselect接口,則創(chuàng)建為實例調(diào)用selectImprot方法,然后遞歸調(diào)用處理import
                //2. 實現(xiàn)importRegistry接口,則緩存到importBeanDefinitionRegistrars集合
                //3. 非上述接口,則當做配置類處理。解析@PropertySources、@ComponentScans、@Import、@Bean
                processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);
            } catch (BeanDefinitionStoreException ex) {
                throw ex;
            } catch (Throwable ex) {
                throw new BeanDefinitionStoreException(
                        "Failed to process import candidates for configuration class [" +
                                configClass.getMetadata().getClassName() + "]", ex);
            }
        }
    }

上述代碼主要流程:

  1. 配置類解析器進行解析

    • 注解方式解析
      • 解析啟動類@ComponentScans注解信息獲取basePackages、basePackageClasses?,沒有則將啟動類包路徑
      • 創(chuàng)建ClassPathBeanDefinitionScanner對當前包以及子包下所有后綴.class文件進行掃描解析
        @Component、@Controller、@Service@Repository
        以及@Configura配置類的@PropertySources、@Import@Bean生成ConfigurationClass
      • ConfigurationClassexcludeFilters進行排除過濾、Conditional進行條件匹配
    • 處理啟動類上的@Import擴展點
  2. 將所有ConfigurationClass解析成BeanDefinition與?@ConditiOnXXX?進行條件匹配,最后注冊到BeanDefinition容器中

@bean 等價于 factory-method
@bean 所在的類 等價于 factory-bean

自動裝配核心邏輯 - AutoConfigurationImportSelector
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
        ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {

    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        }
        //加載組件自動配置類元信息spring-autoconfigure-metadata.properties 
        AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
                .loadMetadata(this.beanClassLoader);
        AnnotationAttributes attributes = getAttributes(annotationMetadata);
        //獲取key為EnableAutoConfiuration對應的value集合
        List<String> configurations = getCandidateConfigurations(annotationMetadata,
                attributes);
        //自動裝配類去重
        configurations = removeDuplicates(configurations);
        Set<String> exclusions = getExclusions(annotationMetadata, attributes);
        checkExcludedClasses(configurations, exclusions);
        configurations.removeAll(exclusions);
        //根據(jù)maven導入的啟動器,過濾出需要導入的自動裝配類
        configurations = filter(configurations, autoConfigurationMetadata);
        fireAutoConfigurationImportEvents(configurations, exclusions);
        return StringUtils.toStringArray(configurations);
    }

上面這段代碼主要做了四件事

  1. 加載spring-autoconfigure-metadata.properties文件得到組件自動裝配類元信息
  2. Spring SPI?本地緩存中獲取keyEnableAutoConfiuration對應的自動裝配類集合
  3. 使用LinkedHashSet對自動裝配類做去重操作
  4. 將自動配置類與spring-autoconfigure-metadata.properties進行條件匹配過濾出需要導入的自動裝配類 (例如?@ConditionalOnClass?)
  5. 返回自動裝配類數(shù)組

通過本文前部分的注解分析已知AutoConfigurationImportSelector實現(xiàn)ImportSelector接口。當ConfigurationClassPostProcessor后置處理器處理@Import時,就會觸發(fā)自動裝配核心類AutoConfigurationImportSelector#selectImprot()獲取Spring SPI?本地緩存keyEnableAutoConfiuration的自動裝配類集合,然后去重過濾返回需要導入的自動裝配類數(shù)組。

三、小結(jié)

簡單的來說,Spring Boot的自動裝配原理主要依賴于Spring SPI機制+@Import擴展點+?ConfigurationClassPostProcessor實現(xiàn)。ConfigurationClassPostProcessor后置處理器會在掃描解析啟動類當前包以及子包下的配置類,并將其注冊為Spring管理的BeanDefinition,從而實現(xiàn)自動裝配。而AutoConfigurationImportSelector作為自動裝配核心類,在處理@Import邏輯中觸發(fā)自動裝配的過程,最終獲取需要導入的自動裝配類集合,實現(xiàn)Spring Boot的自動裝配功能。文章來源地址http://www.zghlxwxcb.cn/news/detail-802925.html

到了這里,關(guān)于Spring Boot源碼解析 - 自動裝配原理的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務器費用

相關(guān)文章

  • spring boot的自動裝配原理

    作者: 逍遙Sean 簡介:一個主修Java的Web網(wǎng)站游戲服務器后端開發(fā)者 主頁:https://blog.csdn.net/Ureliable 覺得博主文章不錯的話,可以三連支持一下~ 如有需要我的支持,請私信或評論留言! Spring Boot是一個開源的Java框架,可以幫助開發(fā)者快速構(gòu)建基于Spring的應用程序。Spring Boo

    2024年02月10日
    瀏覽(29)
  • Spring Boot中自動裝配機制的原理

    Spring Boot中自動裝配機制的原理

    1 .自動裝配,簡單來說就是自動把第三方組件的Bean裝載到Spring IOC容器里面 ,不需要開發(fā)人員再去寫B(tài)ean的裝配配置, 2.在Spring Boot應用里面,只需要在啟動類加上 @SpringBootApplication 注解就可以實現(xiàn)自動裝配。 3.@SpringBootApplication是一個復合注解, 真正實現(xiàn)自動裝配的注解是@

    2024年02月10日
    瀏覽(23)
  • 【Spring Boot自動裝配原理詳解與常見面試題】—— 每天一點小知識

    【Spring Boot自動裝配原理詳解與常見面試題】—— 每天一點小知識

    ????????????????????????????????????????????????????????????? ?? S p r i n g B o o t 自動裝配原理詳解與常見面試題 color{#FF1493}{Spring Boot自動裝配原理詳解與常見面試題} Sp r in g B oo t 自動裝配原理詳解與常見面試題 ?? ????????? ?? 仰望天空

    2024年02月16日
    瀏覽(21)
  • 拆解Spring boot:Springboot為什么如此絲滑而簡單?源碼剖析解讀自動裝配

    拆解Spring boot:Springboot為什么如此絲滑而簡單?源碼剖析解讀自動裝配

    ????歡迎光臨,終于等到你啦???? ??我是蘇澤,一位對技術(shù)充滿熱情的探索者和分享者。???? ??持續(xù)更新的專欄 《Spring 狂野之旅:從入門到入魔》 ?? 本專欄帶你從Spring入門到入魔 ? 這是蘇澤的個人主頁可以看到我其他的內(nèi)容哦???? 努力的蘇澤 http://suzee.blog.csdn

    2024年03月23日
    瀏覽(24)
  • spring boot自動裝配及自動裝配條件判斷

    spring boot自動裝配及自動裝配條件判斷

    第一步需要在pom.xml文件指定需要導入的坐標 要是沒有自動提示需要檢查maven有沒有 實現(xiàn)代碼 執(zhí)行代碼示例

    2024年02月20日
    瀏覽(23)
  • Spring Boot自動裝配

    Spring Boot自動裝配

    自動裝配是 Spring Boot 最核心的功能之一,第三方可以基于這個特性非常方便的和 Spring 做整合,實現(xiàn)自己的 Starter,做到開箱即用。 Java 早期并不支持注解,所以那會兒 Spring 只能通過 xml 的形式來配置。早期項目里要引入一個功能模塊,首先我們要引入 SDK,然后在 xml 里配置

    2024年01月23日
    瀏覽(36)
  • 深入了解Spring Boot自動裝配

    Spring Boot的自動裝配是一項強大的功能,能夠簡化應用程序的配置和開發(fā)過程。讓我們通過一系列詳細的例子來深入了解這一特性。 在Spring Boot中,自動裝配是指框架根據(jù)應用程序的依賴關(guān)系,自動配置和裝配相應的Bean,而無需手動設(shè)置。這使得開發(fā)者可以更專注于業(yè)務邏輯

    2024年01月23日
    瀏覽(30)
  • Spring Boot如何實現(xiàn)自動裝配

    Spring Boot的自動裝配是它的一大特點,可以大大提高開發(fā)效率,減少重復性代碼的編寫。本文將詳細講解Spring Boot如何實現(xiàn)自動裝配。 在傳統(tǒng)的Spring框架中,我們需要手動配置和管理Bean的依賴關(guān)系,但在Spring Boot中,大量的配置可以自動完成。這是因為Spring Boot中引入了自動裝

    2024年02月04日
    瀏覽(21)
  • spring自動裝配原理

    spring自動裝配原理

    為了搞明白自動裝配原理,需要知道spring容器管理bean的生命周期 分為四步: 1、實例化 讀取spring配置文件 通過反射進行bean的實例化(eg:通過BeanFactory實例化) 2、屬性賦值 解析 自動裝配 (byName、byType、constractor、default)DI的體現(xiàn) 循環(huán)依賴 3、初始化 調(diào)用XXXAware回調(diào)方法

    2024年02月02日
    瀏覽(22)
  • 【Spring】深究SpringBoot自動裝配原理

    【Spring】深究SpringBoot自動裝配原理

    早期的 Spring 項目需要添加需要配置繁瑣的 xml ,比如 MVC 、事務、數(shù)據(jù)庫連接等繁瑣的配置。 Spring Boot 的出現(xiàn)就無需這些繁瑣的配置,因為 Spring Boot 基于 約定大于配置 的理念,在項目啟動時候,將約定的配置類自動裝配到 IOC 容器里。 這些都因為 Spring Boot 有自動裝配的特性

    2024年02月14日
    瀏覽(46)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包