最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot自動(dòng)裝配原理及過程解讀

 更新時(shí)間:2025年09月23日 09:55:52   作者:埃澤漫筆  
文章解析SpringBoot自動(dòng)裝配機(jī)制,結(jié)合SPI源碼分析與手寫Starter實(shí)踐,闡述如何通過ServiceLoader和SpringFactoriesLoader實(shí)現(xiàn)服務(wù)發(fā)現(xiàn)及動(dòng)態(tài)配置加載,并利用條件注解@Conditional進(jìn)行智能過濾,最終指導(dǎo)開發(fā)者自定義Starter并配置屬性提示

一、SPI源碼分析

為什么要講SPI呢?因?yàn)樵赟pringBoot的自動(dòng)裝配中其實(shí)有使用到SPI機(jī)制,所以掌握了這部分對于SpringBoot的學(xué)習(xí)還是很有幫助的。

SPI ,全稱為 Service Provider Interface,是一種服務(wù)發(fā)現(xiàn)機(jī)制。它通過在ClassPath路徑下的 META-INF/services 文件夾查找文件,自動(dòng)加載文件里所定義的類。這一機(jī)制為很多框架擴(kuò)展提供了可能,比如在Dubbo、JDBC中都使用到了SPI機(jī)制。我們先通過一個(gè)很簡單的例子來看下它是怎么用的。

案例介紹

先定義接口項(xiàng)目

然后創(chuàng)建一個(gè)擴(kuò)展的實(shí)現(xiàn),先導(dǎo)入上面接口項(xiàng)目的依賴

<dependencies>
         <dependency>
             <groupId>com.bobo</groupId>
             <artifactId>JavaSPIBase</artifactId>
             <version>1.0-SNAPSHOT</version>
         </dependency>
     </dependencies>

然后創(chuàng)建接口的實(shí)現(xiàn)

/**
  * SPI:MySQL對于 baseURL 的一種實(shí)現(xiàn)
  */
 public class MySQLData implements BaseData {
     @Override
     public void baseURL() {
         System.out.println("mysql 的擴(kuò)展實(shí)現(xiàn)....");
     }
 }

然后在resources目錄下創(chuàng)建 META-INF/services 目錄,然后在目錄中創(chuàng)建一個(gè)文件,名稱必須是定義的接口的全類路徑名稱。然后在文件中寫上接口的實(shí)現(xiàn)類的全類路徑名稱。

同樣的再創(chuàng)建一個(gè)案例

然后在測試的項(xiàng)目中測試

public static void main(String[] args) {
         ServiceLoader<BaseData> providers = ServiceLoader.load(BaseData.class);
         Iterator<BaseData> iterator = providers.iterator();
         while(iterator.hasNext()){
             BaseData next = iterator.next();
             next.baseURL();
         }
     }

根據(jù)不同的導(dǎo)入,執(zhí)行的邏輯會有不同

源碼查看

  • ServiceLoader

首先來看下ServiceLoader的類結(jié)構(gòu)

// 配置文件的路徑
     private static final String PREFIX = "META-INF/services/";
 
     // 加載的服務(wù)  類或者接口
     private final Class<S> service;
 
     // 類加載器
     private final ClassLoader loader;
 
     // 訪問權(quán)限的上下文對象
     private final AccessControlContext acc;
 
     // 保存已經(jīng)加載的服務(wù)類
     private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
 
     // 內(nèi)部類,真正加載服務(wù)類
     private LazyIterator lookupIterator;
  • load

load方法創(chuàng)建了一些屬性,重要的是實(shí)例化了內(nèi)部類,LazyIterator。

public final class ServiceLoader<S> implements Iterable<S>
     private ServiceLoader(Class<S> svc, ClassLoader cl) {
         //要加載的接口
         service = Objects.requireNonNull(svc, "Service interface cannot be null");
         //類加載器
         loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
         //訪問控制器
         acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
          reload();
         
     }
     public void reload() {
         //先清空
         providers.clear();
         //實(shí)例化內(nèi)部類 
         LazyIterator lookupIterator = new LazyIterator(service, loader);
     }
 }

查找實(shí)現(xiàn)類和創(chuàng)建實(shí)現(xiàn)類的過程,都在LazyIterator完成。

當(dāng)我們調(diào)用iterator.hasNext和iterator.next方法的時(shí)候,實(shí)際上調(diào)用的都是LazyIterator的相應(yīng)方法。

private class LazyIterator implements Iterator<S>{
     Class<S> service;
     ClassLoader loader;
     Enumeration<URL> configs = null;
     Iterator<String> pending = null;
     String nextName = null; 
     private boolean hasNextService() {
         //第二次調(diào)用的時(shí)候,已經(jīng)解析完成了,直接返回
         if (nextName != null) {
             return true;
         }
         if (configs == null) {
             //META-INF/services/ 加上接口的全限定類名,就是文件服務(wù)類的文件
             //META-INF/services/com.viewscenes.netsupervisor.spi.SPIService
             String fullName = PREFIX + service.getName();
             //將文件路徑轉(zhuǎn)成URL對象
             configs = loader.getResources(fullName);
         }
         while ((pending == null) || !pending.hasNext()) {
             //解析URL文件對象,讀取內(nèi)容,最后返回
             pending = parse(service, configs.nextElement());
         }
         //拿到第一個(gè)實(shí)現(xiàn)類的類名
         nextName = pending.next();
         return true;
     }
 }

創(chuàng)建實(shí)例對象,當(dāng)然,調(diào)用next方法的時(shí)候,實(shí)際調(diào)用到的是,lookupIterator.nextService。

它通過反射的方式,創(chuàng)建實(shí)現(xiàn)類的實(shí)例并返回。

private class LazyIterator implements Iterator<S>{
     private S nextService() {
         //全限定類名
         String cn = nextName;
         nextName = null;
         //創(chuàng)建類的Class對象
         Class<?> c = Class.forName(cn, false, loader);
         //通過newInstance實(shí)例化
         S p = service.cast(c.newInstance());
         //放入集合,返回實(shí)例
         providers.put(cn, p);
         return p; 
     }
 }

看到這兒,我想已經(jīng)很清楚了。獲取到類的實(shí)例,我們自然就可以對它為所欲為了!

二、自動(dòng)裝配源碼分析

在前面的分析中,Spring Framework一直在致力于解決一個(gè)問題,就是如何讓bean的管理變得更簡單,如何讓開發(fā)者盡可能的少關(guān)注一些基礎(chǔ)化的bean的配置,從而實(shí)現(xiàn)自動(dòng)裝配。所以,所謂的自動(dòng)裝配,實(shí)際上就是如何自動(dòng)將bean裝載到Ioc容器中來。

實(shí)際上在spring 3.x版本中,Enable模塊驅(qū)動(dòng)注解的出現(xiàn),已經(jīng)有了一定的自動(dòng)裝配的雛形,而真正能夠?qū)崿F(xiàn)這一機(jī)制,還是在spirng 4.x版本中,conditional條件注解的出現(xiàn)。ok,我們來看一下spring boot的自動(dòng)裝配是怎么一回事。

自動(dòng)裝配的演示

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
 </dependency>
spring:
    redis:
      host: 127.0.0.1 
      port: 6379
@Autowired
    private RedisTemplate<String,String>redisTemplate;

按照下面的順序添加starter,然后添加配置,使用RedisTemplate就可以使用了? 那大家想沒想過一個(gè)問題,為什么RedisTemplate可以被直接注入?它是什么時(shí)候加入到Ioc容器的呢? 這就是自動(dòng)裝配。自動(dòng)裝配可以使得classpath下依賴的包相關(guān)的bean,被自動(dòng)裝載到Spring Ioc容器中,怎么做到的呢?

深入分析EnableAutoConfiguration

EnableAutoConfiguration的主要作用其實(shí)就是幫助springboot應(yīng)用把所有符合條件的@Configuration配置都加載到當(dāng)前SpringBoot創(chuàng)建并使用的IoC容器中。

再回到EnableAutoConfiguration這個(gè)注解中,我們發(fā)現(xiàn)它的import是這樣

@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

但是從EnableAutoCOnfiguration上面的import注解來看,這里面并不是引入另外一個(gè)Configuration。而是一個(gè)ImportSelector。這個(gè)是什么東西呢?

AutoConfigurationImportSelector是什么?

Enable注解不僅僅可以像前面演示的案例一樣很簡單的實(shí)現(xiàn)多個(gè)Configuration的整合,還可以實(shí)現(xiàn)一些復(fù)雜的場景,比如可以根據(jù)上下文來激活不同類型的bean,@Import注解可以配置三種不同的class

第一種就是前面演示過的,基于普通bean或者帶有@Configuration的bean進(jìn)行諸如

實(shí)現(xiàn)ImportSelector接口進(jìn)行動(dòng)態(tài)注入

實(shí)現(xiàn)ImportBeanDefinitionRegistrar接口進(jìn)行動(dòng)態(tài)注入

  • CacheService:
public class CacheService {}
  • LoggerService:
public class LoggerService {}
  • EnableDefineService:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented 
@Inherited  --允許被繼承
@Import({MyDefineImportSelector.class})
public @interface EnableDefineService {

    String[] packages() default "";
}
  • MyDefineImportSelector:
public class MyDefineImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        //獲得指定注解的詳細(xì)信息。我們可以根據(jù)注解中配置的屬性來返回不同的class,
        //從而可以達(dá)到動(dòng)態(tài)開啟不同功能的目的
    
annotationMetadata.getAllAnnotationAttributes(EnableDefineService.class.getName(),true)
            .forEach((k,v) -> {
                log.info(annotationMetadata.getClassName());
                log.info("k:{},v:{}",k,String.valueOf(v));
            });
        return new String[]{CacheService.class.getName()};
    }
}
  • EnableDemoTest:
@SpringBootApplication
@EnableDefineService(name = "aizer",value = "aizer")
public class EnableDemoTest {
    public static void main(String[] args) {
        ConfigurableApplicationContext ca=SpringApplication.run(EnableDemoTest.class,args);
        System.out.println(ca.getBean(CacheService.class));
        System.out.println(ca.getBean(LoggerService.class));
    }
}

了解了selector的基本原理之后,后續(xù)再去分析AutoConfigurationImportSelector的原理就很簡單了,它本質(zhì)上也是對于bean的動(dòng)態(tài)加載。

@EnableAutoConfiguration注解的實(shí)現(xiàn)原理

了解了ImportSelector和ImportBeanDefinitionRegistrar后,對于EnableAutoConfiguration的理解就容易一些了

它會通過import導(dǎo)入第三方提供的bean的配置類:AutoConfigurationImportSelector

@Import(AutoConfigurationImportSelector.class)

從名字來看,可以猜到它是基于ImportSelector來實(shí)現(xiàn)基于動(dòng)態(tài)bean的加載功能。之前我們講過Springboot @Enable*注解的工作原理ImportSelector接口selectImports返回的數(shù)組(類的全類名)都會被納入到spring容器中。

那么可以猜想到這里的實(shí)現(xiàn)原理也一定是一樣的,定位到AutoConfigurationImportSelector這個(gè)類中的selectImports方法

  • selectImports:
public String[] selectImports(AnnotationMetadata annotationMetadata) {
   if (!isEnabled(annotationMetadata)) {
      return NO_IMPORTS;
   }
// 從配置文件(spring-autoconfigure-metadata.properties)中加載 AutoConfigurationMetadata
   AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
         .loadMetadata(this.beanClassLoader);
// 獲取所有候選配置類EnableAutoConfiguration
   AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(
         autoConfigurationMetadata, annotationMetadata);
   return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
  • getAutoConfigurationEntry:
protected AutoConfigurationEntry getAutoConfigurationEntry(
      AutoConfigurationMetadata autoConfigurationMetadata,
      AnnotationMetadata annotationMetadata) {
   if (!isEnabled(annotationMetadata)) {
      return EMPTY_ENTRY;
   }
//獲取元注解中的屬性
   AnnotationAttributes attributes = getAttributes(annotationMetadata);
//使用SpringFactoriesLoader 加載classpath路徑下META-INF\spring.factories中,
//key= org.springframework.boot.autoconfigure.EnableAutoConfiguration對應(yīng)的value
   List<String> configurations = getCandidateConfigurations(annotationMetadata,
         attributes);
//去重
   configurations = removeDuplicates(configurations);
//應(yīng)用exclusion屬性
   Set<String> exclusions = getExclusions(annotationMetadata, attributes);
   checkExcludedClasses(configurations, exclusions);
   configurations.removeAll(exclusions);
//過濾,檢查候選配置類上的注解@ConditionalOnClass,如果要求的類不存在,則這個(gè)候選類會被過濾不被加載
   configurations = filter(configurations, autoConfigurationMetadata);
   //廣播事件
fireAutoConfigurationImportEvents(configurations, exclusions);
   return new AutoConfigurationEntry(configurations, exclusions);
}

本質(zhì)上來說,其實(shí)EnableAutoConfiguration會幫助springboot應(yīng)用把所有符合@Configuration配置都加載到當(dāng)前SpringBoot創(chuàng)建的IoC容器,而這里面借助了Spring框架提供的一個(gè)工具類SpringFactoriesLoader的支持。以及用到了Spring提供的條件注解@Conditional,選擇性的針對需要加載的bean進(jìn)行條件過濾

SpringFactoriesLoader

為了給大家補(bǔ)一下基礎(chǔ),我在這里簡單分析一下SpringFactoriesLoader這個(gè)工具類的使用。它其實(shí)和java中的SPI機(jī)制的原理是一樣的,不過它比SPI更好的點(diǎn)在于不會一次性加載所有的類,而是根據(jù)key進(jìn)行加載。

首先,SpringFactoriesLoader的作用是從classpath/META-INF/spring.factories文件中,根據(jù)key來加載對應(yīng)的類到spring IoC容器中。接下來帶大家實(shí)踐一下

  • 創(chuàng)建外部項(xiàng)目jar:
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>4.3.13.RELEASE</version>
</dependency>
  • 創(chuàng)建bean以及config:
public class aizerCore {
    public String study(){
        System.out.println("good good study, day day up");
        return "aizerEdu.com";
    }
}
@Configuration
public class aizerConfig {
    @Bean
    public aizerCore aizerCore(){
        return new aizerCore();
    }
}
  • 創(chuàng)建另外一個(gè)工程(spring-boot):

把前面的工程打包成jar,當(dāng)前項(xiàng)目依賴該jar包

<dependency>
    <groupId>com.aizeredu.practice</groupId>
    <artifactId>aizer-Core</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>
  • 通過下面代碼獲取依賴包中的屬性:

運(yùn)行結(jié)果會報(bào)錯(cuò),原因是aizerCore并沒有被Spring的IoC容器所加載,也就是沒有被EnableAutoConfiguration導(dǎo)入

@SpringBootApplication
public class SpringBootStudyApplication {
    public static void main(String[] args) throws IOException {
        ConfigurableApplicationContext ac=SpringApplication.run(SpringBootStudyApplication.class, args);
        aizerCore Myc=ac.getBean(aizerCore.class);
        System.out.println(Myc.study());
    }
}
  • 解決方案:

在aizer-Core項(xiàng)目resources下新建文件夾META-INF,在文件夾下面新建spring.factories文件,文件中配置,key為自定配置類EnableAutoConfiguration的全路徑,value是配置類的全路徑

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.aizeredu.practice.aizerConfig

重新打包,重新運(yùn)行SpringBootStudyApplication這個(gè)類。

可以發(fā)現(xiàn),我們編寫的那個(gè)類,就被加載進(jìn)來了。

Spring Boot中的條件過濾

在分析AutoConfigurationImportSelector的源碼時(shí),會先掃描spring-autoconfiguration-metadata.properties文件,最后在掃描spring.factories對應(yīng)的類時(shí),會結(jié)合前面的元數(shù)據(jù)進(jìn)行過濾,為什么要過濾呢?

原因是很多的@Configuration其實(shí)是依托于其他的框架來加載的,如果當(dāng)前的classpath環(huán)境下沒有相關(guān)聯(lián)的依賴,則意味著這些類沒必要進(jìn)行加載,所以,通過這種條件過濾可以有效的減少@configuration類的數(shù)量從而降低SpringBoot的啟動(dòng)時(shí)間。

修改aizer-Core:

在META-INF/增加配置文件,spring-autoconfigure-metadata.properties。

com.aizeredu.practice.aizerConfig.ConditionalOnClass=com.aizeredu.TestClass

格式:自動(dòng)配置的類全名.條件=值

上面這段代碼的意思就是,如果當(dāng)前的classpath下存在TestClass,則會對aizerConfig這個(gè)Configuration進(jìn)行加載

演示過程(spring-boot):

沿用前面spring-boot工程的測試案例,直接運(yùn)行main方法,發(fā)現(xiàn)原本能夠被加載的aizerCore,發(fā)現(xiàn)在ioc容器中找不到了。

public static void main(String[] args) throws IOException {
    ConfigurableApplicationContext ac=SpringApplication.run(SpringBootStudyApplication.class, args);
    aizerCore Myc=ac.getBean(aizerCore.class);
    System.out.println(Myc.study());
}

在當(dāng)前工程中指定的包c(diǎn)om.aizeredu下創(chuàng)建一個(gè)TestClass以后,再運(yùn)行上面這段代碼,程序能夠正常執(zhí)行

三、手寫Starter

我們通過手寫Starter來加深對于自動(dòng)裝配的理解

1.創(chuàng)建一個(gè)Maven項(xiàng)目,quick-starter

定義相關(guān)的依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <version>2.1.6.RELEASE</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.56</version>
    <!-- 可選 -->
    <optional>true</optional>
</dependency>

2.定義Formate接口

定義的格式轉(zhuǎn)換的接口,并且定義兩個(gè)實(shí)現(xiàn)類

public interface FormatProcessor {
    /**
     * 定義一個(gè)格式化的方法
     * @param obj
     * @param <T>
     * @return
     */
    <T> String formate(T obj);
}
public class JsonFormatProcessor implements FormatProcessor {
    @Override
    public <T> String formate(T obj) {
        return "JsonFormatProcessor:" + JSON.toJSONString(obj);
    }
}
public class StringFormatProcessor implements FormatProcessor {
    @Override
    public <T> String formate(T obj) {
        return "StringFormatProcessor:" + obj.toString();
    }
}

3.定義相關(guān)的配置類

首先定義格式化加載的Java配置類

@Configuration
public class FormatAutoConfiguration {

    @ConditionalOnMissingClass("com.alibaba.fastjson.JSON")
    @Bean
    @Primary // 優(yōu)先加載
    public FormatProcessor stringFormatProcessor(){
        return new StringFormatProcessor();
    }

    @ConditionalOnClass(name="com.alibaba.fastjson.JSON")
    @Bean
    public FormatProcessor jsonFormatProcessor(){
        return new JsonFormatProcessor();
    }
}

定義一個(gè)模板工具類

public class HelloFormatTemplate {

    private FormatProcessor formatProcessor;


    public HelloFormatTemplate(FormatProcessor processor){
        this.formatProcessor = processor;
    }

    public <T> String doFormat(T obj){
        StringBuilder builder = new StringBuilder();
        builder.append("Execute format : ").append("<br>");
        builder.append("Object format result:" ).append(formatProcessor.formate(obj));
        return builder.toString();
    }
}

再就是整合到SpringBoot中去的Java配置類

@Configuration
@Import(FormatAutoConfiguration.class)
public class HelloAutoConfiguration {

    @Bean
    public HelloFormatTemplate helloFormatTemplate(FormatProcessor formatProcessor){
        return new HelloFormatTemplate(formatProcessor);
    }
}

4.創(chuàng)建spring.factories文件

在resources下創(chuàng)建META-INF目錄,再在其下創(chuàng)建spring.factories文件

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  org.aizeredu.autoconfiguration.HelloAutoConfiguration

install 打包,然后就可以在SpringBoot項(xiàng)目中依賴改項(xiàng)目來操作了。

5.測試

在SpringBoot中引入依賴

<dependency>
    <groupId>org.example</groupId>
    <artifactId>format-spring-boot-starter</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

在controller中使用

@RestController
public class UserController {

    @Autowired
    private HelloFormatTemplate helloFormatTemplate;

    @GetMapping("/format")
    public String format(){
        User user = new User();
        user.setName("BoBo");
        user.setAge(18);
        return helloFormatTemplate.doFormat(user);
    }
}

6.自定義Starter關(guān)聯(lián)配置信息

有些情況下我們可以需要用戶在使用的時(shí)候動(dòng)態(tài)的傳遞相關(guān)的配置信息,比如Redis的Ip,端口等等,這些信息顯然是不能直接寫到代碼中的,這時(shí)我們就可以通過SpringBoot的配置類來實(shí)現(xiàn)。

首先引入依賴支持

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <version>2.2.6.RELEASE</version>
    <optional>true</optional>
</dependency>

然后創(chuàng)建對應(yīng)的屬性類

@ConfigurationProperties(prefix = HelloProperties.HELLO_FORMAT_PREFIX)
public class HelloProperties {

    public static final String HELLO_FORMAT_PREFIX="aizer.hello.format";

    private String name;

    private Integer age;

    private Map<String,Object> info;

    public Map<String, Object> getInfo() {
        return info;
    }

    public void setInfo(Map<String, Object> info) {
        this.info = info;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

然后再Java配置類中關(guān)聯(lián)

@Configuration
@Import(FormatAutoConfiguration.class)
@EnableConfigurationProperties(HelloProperties.class)
public class HelloAutoConfiguration {

    @Bean
    public HelloFormatTemplate helloFormatTemplate(HelloProperties helloProperties,FormatProcessor formatProcessor){
        return new HelloFormatTemplate(helloProperties,formatProcessor);
    }
}

調(diào)整模板方法

public class HelloFormatTemplate {

    private FormatProcessor formatProcessor;

    private HelloProperties helloProperties;

    public HelloFormatTemplate(HelloProperties helloProperties,FormatProcessor processor){
        this.helloProperties = helloProperties;
        this.formatProcessor = processor;
    }

    public <T> String doFormat(T obj){
        StringBuilder builder = new StringBuilder();
        builder.append("Execute format : ").append("<br>");
        builder.append("HelloProperties:").append(formatProcessor.formate(helloProperties.getInfo())).append("<br>");
        builder.append("Object format result:" ).append(formatProcessor.formate(obj));
        return builder.toString();
    }
}

增加提示

在這個(gè)工程的META-INF/下創(chuàng)建一個(gè)additional-spring-configuration-metadata.json,這個(gè)是設(shè)置屬性的提示類型

{
  "properties": [
    {
      "name": "aizer.hello.format.name",
      "type": "java.lang.String",
      "description": "賬號信息",
      "defaultValue": "root"
    },{
      "name": "aizer.hello.format.age",
      "type": "java.lang.Integer",
      "description": "年齡",
      "defaultValue": 18
    }
  ]
}
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
        // 加載當(dāng)前系統(tǒng)下 META-INF/spring.factories 文件中聲明的配置類
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
        // 移除掉重復(fù)的
		configurations = removeDuplicates(configurations);
        // 移除掉顯示排除的
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
        // 過濾掉不需要載入的配置類
		configurations = getConfigurationClassFilter().filter(configurations);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java實(shí)現(xiàn)線程的暫停和恢復(fù)的示例詳解

    Java實(shí)現(xiàn)線程的暫停和恢復(fù)的示例詳解

    這幾天的項(xiàng)目中,客戶給了個(gè)需求,希望我可以開啟一個(gè)任務(wù),想什么時(shí)候暫停就什么時(shí)候暫停,想什么時(shí)候開始就什么時(shí)候開始,所以本文小編給大家介紹了Java實(shí)現(xiàn)線程的暫停和恢復(fù)的示例,需要的朋友可以參考下
    2023-11-11
  • java播放聲音類和一個(gè)簡單示例

    java播放聲音類和一個(gè)簡單示例

    這篇文章主要介紹了一個(gè)java播放聲音類和一個(gè)java播放聲音的應(yīng)用程序,應(yīng)用程序可以單次播放聲音、循環(huán)播放聲音,需要的朋友可以參考下
    2014-03-03
  • Java參數(shù)校驗(yàn)詳解之使用@Valid注解和自定義注解進(jìn)行參數(shù)驗(yàn)證

    Java參數(shù)校驗(yàn)詳解之使用@Valid注解和自定義注解進(jìn)行參數(shù)驗(yàn)證

    在后端開發(fā)中,參數(shù)校驗(yàn)是非常普遍的,下面這篇文章主要給大家介紹了關(guān)于Java參數(shù)校驗(yàn)詳解之使用@Valid注解和自定義注解進(jìn)行參數(shù)驗(yàn)證的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-06-06
  • java 根據(jù)前端返回的字段名進(jìn)行查詢數(shù)據(jù)

    java 根據(jù)前端返回的字段名進(jìn)行查詢數(shù)據(jù)

    本文介紹了如何在Java中使用SpringDataJPA實(shí)現(xiàn)動(dòng)態(tài)查詢功能,以便根據(jù)前端傳遞的字段名動(dòng)態(tài)構(gòu)建查詢語句,通過創(chuàng)建實(shí)體類、Repository接口、構(gòu)建動(dòng)態(tài)查詢、在Service層和Controller中使用動(dòng)態(tài)查詢,實(shí)現(xiàn)了前后端分離架構(gòu)中的靈活查詢需求
    2024-11-11
  • Java中將UUID存儲為Base64字符串的方法實(shí)現(xiàn)

    Java中將UUID存儲為Base64字符串的方法實(shí)現(xiàn)

    使用Base64編碼來對UUID存儲在一些特定的場合被廣泛的使用,本文主要介紹了Java中將UUID存儲為Base64字符串的方法實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-04-04
  • Mybatis-plus實(shí)現(xiàn)join連表查詢的示例代碼

    Mybatis-plus實(shí)現(xiàn)join連表查詢的示例代碼

    mybatis-plus在連表查詢上是不行的,如果需要連表查詢,就得乖乖的去寫xml文件了,本文介紹了mybatis-plus-join框架,它支持連表查詢,感興趣的可以了解一下
    2023-08-08
  • JDK源碼Enum類原理及代碼實(shí)例解析

    JDK源碼Enum類原理及代碼實(shí)例解析

    這篇文章主要介紹了JDK源碼Enum類原理及代碼實(shí)例解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-11-11
  • java的Guava工具包介紹

    java的Guava工具包介紹

    Java開發(fā)的同學(xué)應(yīng)該都使用或者聽說過Google提供的Guava工具包。日常使用最多的肯定是集合相關(guān)的工具類,還有Guava cache,除了這些之外Guava還提供了很多有用的功能,鑒于日常想用的時(shí)候找不到,這里就梳理一下Guava中那些好用的工具類,想優(yōu)化代碼的時(shí)候不妨過來看看
    2021-04-04
  • SpringBoot通過ThreadLocal實(shí)現(xiàn)登錄攔截詳解流程

    SpringBoot通過ThreadLocal實(shí)現(xiàn)登錄攔截詳解流程

    這篇文章主要介紹了SpringBoot(HandlerInterceptor)+ThreadLocal實(shí)現(xiàn)登錄攔截,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • 解決ThingsBoard編譯報(bào)錯(cuò)問題:Failure?to?find?org.gradle:gradle-tooling-api:jar:6.3

    解決ThingsBoard編譯報(bào)錯(cuò)問題:Failure?to?find?org.gradle:gradle-too

    這篇文章主要介紹了ThingsBoard編譯報(bào)錯(cuò):Failure?to?find?org.gradle:gradle-tooling-api:jar:6.3,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-03-03

最新評論

卓资县| 游戏| 沙坪坝区| 祁连县| 霍林郭勒市| 灵璧县| 麟游县| 玉林市| 肃宁县| 苏尼特左旗| 隆化县| 嘉峪关市| 宜川县| 儋州市| 西峡县| 海城市| 通道| 石首市| 九龙坡区| 随州市| 益阳市| 兰考县| 观塘区| 德保县| 鄂托克前旗| 广西| 胶南市| 祁连县| 遂昌县| 益阳市| 陇川县| 承德市| 阜新市| 长垣县| 万山特区| 岳池县| 普安县| 奎屯市| 郸城县| 清丰县| 盐城市|