SpringBoot自動配置原理解析

碼農談IT發表於2023-11-02

來源:京東雲開發者


一、什麼是SpringBoot自動配置

首先介紹一下什麼是SpringBoot,SpringBoost是基於Spring框架開發出來的功能更強大的Java程式開發框架,其最主要的特點是:能使程式開發者快速搭建一套開發環境。SpringBoot能將主流的開發框架(例如SpringMVC,Dubbo,Mybatis,Redis等),做到像Maven匯入Jar包一樣的簡潔快速,做到開箱即用。其中最關鍵的技術就是SpringBoot定製的各種Starter,通Maven引入Starter就能快速搭建開發環境。


二、SpringBoot Starter自動裝配案例

在以前單獨使用SpringMVC Web程式設計框架時,我們需要單獨配置DispatcherServlet和Tomcat,使用SpringBoot之後,我們只需要引入SpringBoot-Starter-Web就能直接開始編寫Controller等Web相關的程式碼,這就是SpringBoot為們提供的開箱即用的便捷能力,下面就以SpringBoot-Starter-Web來說明SpringBoot自動配置的關鍵原理


三、SpringBoot自動裝配案例原始碼解析

3.1 DispatcherServlet的自動配置原理

首先我們定位到SpringBoot自動配置的Maven依賴





<dependency>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-autoconfigure</artifactId>        <version>${spring-boot.version}</version>      </dependency>
在依賴的Jar包中我們可以在META-INF/spring.factories中找到自動配置類:


org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration
在這個類中存在有一個靜態內部類:
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration.DispatcherServletConfiguration

下圖是這個配置類的主要原始碼和解析:
SpringBoot自動配置原理解析
下面將上圖中關鍵的註解功能,分別進行功能說明

3.1.1:@EnableConfigurationProperties({WebMvcProperties.class})註解解析

這個註解表示使WebMvcProperties.class類上的@ConfigurationProperties這個註解生效,同時@ConfigurationProperties這個註解是將application.xml中以spring.mvc開頭的配置引數自動注入到WebMvcProperties.class類的欄位中

3.1.2:@Conditional({DefaultDispatcherServletCondition.class}註解解析

該註解的原理就是將滿足特定條件情況下的Bean自動載入到Spring容器中,該註解對應的Spring介面就是org.springframework.context.annotation.Condition這個介面

public interface Condition {    boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2);}

3.1.3:@ConditionOnClass註解解析

@ConditionOnClass這個註解是在當程式程式碼環境classpath下存在xxx.class的情況下條件成立,同時最終也會呼叫到matches方法中,其中關鍵的原始碼如下:

protected static Class<?> resolve(String className, ClassLoader classLoader) throws ClassNotFoundException {    return classLoader != null ? Class.forName(className, false, classLoader) : Class.forName(className);}

從上面可以看到,程式碼利用Class.forName方法載入classpath下的xxx.class類,如果載入成功條件就會成立。最後,在滿足了所有@ConditionOnal註解條件後,SpringBoot就會自動為我們在Spring容器中注入DispatcherServlet了,無需單獨配置了,直接引入spring-boot-starter-webr即可開始使用web相關功能。

3.1.4:總結

我們以DispatcherServlet是如何自動配置到容器中為例,探究了SpringBoot Starter的自動配置原理,其中涉及了幾個關鍵的註解和步驟:
第一步:涉及到了配置檔案的讀取和個性化配置,這裡就涉及到了下面這兩個註解

@ConfigurationProperties@EnableConfigurationProperties

第二步:設計到了在什麼條件下才自動配置的註解

@Conditional@ConditionalOnClass

第三步:約定了自動配置類的載入路徑

/META-INF/spring-factoriesorg.springframework.boot.autoconfigure.EnableAutoConfiguration=自動配置類全路徑名稱

在我們瞭解到了SpringBoot自動配置的原理之後,我們就可以自定義一個SpringBoot Starter來快速搭建我們的開發環境了。


四、自定義一個列印輸入輸出日誌的Starter

4.1 首先定義一個標記需要列印出入參日誌的註解@PrintLog

@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface PrintLog {}

4.2 定義一個存放列印日誌配置的實體類

//自動注入application配置檔案中已log.switch開頭的配置引數@ConfigurationProperties("log.switch")public class LogProperties {    //是否啟用列印日誌功能    private Boolean enabled = false;    //是否列印呼叫者ip    private Boolean printIp = false;    //是否列印呼叫者url    private Boolean printUrl = false}

4.3 定義一個@PrintLog註解的切面類


































@Aspectpublic class LogAspect {    private static final Log LOGGER = LogFactory.getLog(LogAspect.class);    private LogProperties logProperties;        @Pointcut("@annotation(com.zl.annotation.PrintLog)")    public void Log(){}
   @Around("Log()")    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();        HttpServletRequest request = attributes.getRequest();        MethodSignature signature = (MethodSignature) joinPoint.getSignature();        Method method = signature.getMethod();        String methodName = method.getName();        //列印呼叫url        if (Boolean.TRUE.equals(logProperties.getPrintUrl())){            LOGGER.info("URL:" + request.getRequestURL().toString());        }        //列印ip        if (Boolean.TRUE.equals(logProperties.getPrintIp())) {            LOGGER.info("IP :" + request.getRemoteAddr());        }        //列印方法        LOGGER.info("method :" + methodName);        //列印引數        LOGGER.info("parameter :" + Arrays.toString(joinPoint.getArgs()));        Object result = joinPoint.proceed();        //列印返回結果        LOGGER.info("return :" + JSON.toJSONString(result));        return result;    }}

4.4 定義一個列印日誌的自動配置類

@Configuration@EnableConfigurationProperties({LogProperties.class})//表示在application配置檔案中必須配置log.switch.enabled = true才啟動自動配置@ConditionalOnProperty(prefix = "log.switch", value = "enabled", havingValue = "true")public class LogAutoConfigure {    @Bean    //Advice.class是aop切面中關鍵的切面方法類(@Before,@After等)    //程式中有Advice.class類說明需要使用切面功能,這時才載入自定義的切面類    @ConditionalOnClass(Advice.class)    public LogAspect webLogAspect(LogProperties logProperties){        return new LogAspect(logProperties);    }}

@ConditionalOnProperty表示在application配置檔案中必須存在相應的配置才能使條件成立

4.5 配置自定義配置類的載入路徑

META-INF/spring.factoriesorg.springframework.boot.autoconfigure.EnableAutoConfiguration=\  com.zl.autoConfigure.LogAutoConfigure

4.6 Maven打包部署

maven install



五、開始使用自定義的Starter

5.1 在專案中引入Starter

<dependency>   <groupId>com.zl.demo</groupId>   <artifactId>LogStarter</artifactId>   <version>1.0-SNAPSHOT</version></dependency>

5.2 在application.yml中配置引數

log:  switch:    enabled: true //啟用列印日誌功能    printIp: true //列印請求ip    printUrl: true //列印請求url

經過上面兩個步驟就,列印日誌的功能就已經開啟了,接下來就可以進行編碼測試了

5.3 定義一個Controller並標上列印日誌的註解

@RestController@RequestMapping("/test")public class HelloWorldController {    @PrintLog    @RequestMapping("/hello")    public String helleWorld(String test){        return "hello world!";    }}

5.4 啟動專案開始測試

com.zl.aspect.LogAspect   : URL:[test]com.zl.aspect.LogAspect   : return :"hello world!"

可以看到上面的入參和返回值都已經列印出來了,說明了自定義的starter已經生效了。


六、總結

SpringBoot自動配置功能帶給我們的是開箱即用,快速便捷的功能,自動配置為我們研發人員帶來的優點,我主要總結為以下兩點:

  1. 提高研發效率。我們可以快速構建開發環境,對於開發中使用到的開源元件和中介軟體,我們直接引入對應的Starter就可以直接開發了,例如Redis和Mybatis等,可以直接引入對應的spring-boot-starter-data-redis就可以直接使用RedisTemplate來操作Redis了,這樣可以極大的提高研發的效率,無需再進行復雜的起步配置了和各種版本依賴管理了。
  2. 標準模組複用對於業務開發中的一些標準模組,例如常用的一些三方服務,我們可以利用Starter直接配置好,在需要使用的專案中直接引入這個starter就可以立即使用了,無需再去引入Jar包和編寫配置檔案等,同樣的,對於一些標準非業務強耦合的功能,例如監控,鑑權等,也可以定義一個Starter,需要使用鑑權和監控功能的專案就可以直接複用了,無需再次開發。

-end-

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024924/viewspace-2992543/,如需轉載,請註明出處,否則將追究法律責任。

相關文章