漫談一下 SpringBoot 的起步依賴和自動配置 起步依賴 什麼是起步依賴 使用起步依賴 覆蓋起步依賴引入的依賴 自動配置

起步依賴

什麼是起步依賴

在沒有SpringBoot之前,如果要使用Spring開發一個web工程,我們需要怎麼做呢?

首先,我們需要添加Spring、SpringMVC的框架的依賴,有時還需要考慮這些依賴間的版本兼容性,我們pom.xml文件看起來往往是這樣的。

<dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
      <scope>provided</scope>
    </dependency>

 </dependencies>

然後,配置web.xml。

<?xml version="1.0" encoding="UTF-8"?>

    <!-- SpringMVC的前端控制器 -->
    <servlet>

        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 設置自己定義的控制器xml文件 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/my-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <!-- Spring MVC配置文件結束 -->

    <!-- 攔截設置 -->
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <!-- 由SpringMVC攔截所有請求 -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>  

</web-app>

然後修改自定義的控制器xml。

<beans> 
    <!-- 把標記了@Controller註解的類轉換爲bean -->
    <context:component-scan base-package="com.mucfc" />
    <!-- 啓動Spring MVC的註解功能,完成請求和註解POJO的映射 -->

    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
    <!-- 對模型視圖名稱的解析,即在模型視圖名稱添加前後綴 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
        p:prefix="/WEB-INF/views/" p:suffix=".jsp"/>

<beans>

而有了SpringBoot後我們只需要在pom.xml文件中繼承SpringBoot並引入web的起步依賴,之後添加啓動類即可。通過對比,SpringBoot明顯簡化了大量的配置,使得我們可以快速搭建一個應用。

SpringBoot提供了非常多的starter(起步依賴),這些starter預先打包好了與常用模塊相關的所有jar包,並完成了自動配置。因此,起步依賴本質上是一個Maven項目對象模型,定義了對其他庫的傳遞依賴,這些組合在一起支持某種特定功能,這就使得我們在開發時不必過多的關注框架配置,從而簡化了開發過程。

使用起步依賴

SpringBoot提供了近50種starter,如上述說的創建一個web工程,我們只需要早pom文件中添加spring-boot-starter-web即可(Spring提供的starter命名規範spring-boot-starter-xxx.jar,第三方提供的starter命名規範xxx-spring-boot-starter.jar),starter的命名往往表明了其能提供的功能。

<dependencies>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
   </dependency>
</dependencies>

如果依賴項沒有指明版本號,SpringBoot會根據自己的版本號自動關聯。如果需要指定特定的版本號,通過元素指定即可。

覆蓋起步依賴引入的依賴

還是以spring-boot-starter-web爲例,spring-boot-starter-web傳遞依賴了Jackson JSON庫,如果你的項目中並不會用到JSON,你可以使用maven的元素將其排除即可(不排除也不會有任何副作用),如下:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
   <exclusions>
      <exclusion>
         <groupId>com.fasterxml.jackson.core</groupId>
         <artifactId>jackson-bom</artifactId>
      </exclusion>
   </exclusions>
</dependency>

另外,如果你想使用另一個版本的Jackson而不是spring-boot-starter-web中自帶的,你只需要在pom.xml文件中添加實際要用的依賴即可,maven會使用pom中的依賴覆蓋starter引入的傳遞依賴。

自動配置

SpringBoot的自動配置使得Spring在運行過程中可以根據不同情況決定使用哪個配置,其實現原理是利用了Spring的條件化配置,條件話配置允許配置存在與應用中,但是隻有在滿足某些特定條件時纔會被使用。

上篇文章中我們提到過,要啓動SpringBoot需要有一個@SpringBootApplication註解的啓動引導類,該類除了是應用的入口,還有着配置SpringBoot的重要作用。上篇文章( 《三種方法帶你新建一個SpringBoot項目》 )中,我們簡單介紹了下@SpringBootApplication,該註解等同於同時使用@Configuration, @EnableAutoConfiguration 和 @ComponentScan默認屬性的情況,而@EnableAutoConfiguration 則是自動配置的關鍵,看下其源碼:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

其核心在於@Import({AutoConfigurationImportSelector.class}),熟悉Spring的都知道@Import的作用是將組件加載到Spring容器中,這裏是將AutoConfigurationImportSelector添加到Spring容器中。AutoConfigurationImportSelector類中的selectImports方法會調用進getCandidateConfigurations方法,該方法的實現如下:

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
    Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
    return configurations;
}

loadFactoryNames會掃描classpath下所有jar包的META-INF/spring.factories文件,將spring.factories文件中key爲EnableAutoConfiguration的所有值取出,這些值就是自動配置類的全限定名,然後通過反射將這些類加載到Spring容器中。打開spring-boot-autoconfigure-2.4.1.RELEASE.jar/META-INF/spring.factories文件並找到EnableAutoConfiguration看一下(只截取前幾行):

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
……

那這些自動配置類是如何被啓用的呢?看個簡單的DispatcherServletAutoConfiguration類,分析下其源碼(只截取前幾行):

@AutoConfigureOrder(-2147483648)
@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
@ConditionalOnClass({DispatcherServlet.class})
@AutoConfigureAfter({ServletWebServerFactoryAutoConfiguration.class})
public class DispatcherServletAutoConfiguration {
    public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet";
    public static final String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = "dispatcherServletRegistration";

    public DispatcherServletAutoConfiguration() {
    }

不難看出該類也被很多註解修飾了,@Configuration表明這是一個配置類。該配置類是否被啓用的關鍵是@ConditionalOnClass註解,在DispatcherServletAutoConfiguration中@ConditionalOnClass指定只有在DispatcherServlet類存在時該配置纔會生效。

除此之外,還有好多@ConditionalOnXXX註解(如:@ConditionalOnWebApplication、@ConditionalOnBean等等),這些註解就是條件註解,只有在滿足條件的情況下,配置類纔會生效。

來源:https://www.tuicool.com/articles/7rEbauE

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章