自定義Spring Boot Starter

在實際開發中,對於一些通用業務和公共組件,咱們可能想將其作成一個Spring Boot Starter便於全部系統使用,這就須要咱們定義本身的Spring Boot Starter。
本文不會編寫一個真正的Spring Boot Starter,而是選擇借用mybatis-spring-boot-starter來描述starter的製做方式。之因此選擇mybatis的spring-boot-starter進行講解,一是考慮到mybatis比較重要,你們都很熟悉。二是mybatis的spring-boot-starter不是spring官方提供的,是由mybatis本身實現的。
先來思考一下,一個Spring Boot Starter都須要具有哪些能力:java

  1. 提供了統一的dependency版本管理。僅須要導入對應的Starter依賴,相關的library,甚至是中間件,都一次性被引入了,並且要保證各dependency之間是不衝突的。例如當咱們引入mybatis-spring-boot-starter依賴,mybatis和mybatis-spring等相關依賴也順帶被導入了。
  2. 提供自動裝配的能力。Starter能夠自動的向Spring容器中注入須要的Bean,而且完成對應的配置。
  3. 對外暴露恰當的properties。Starter不可能提早知道所有的配置信息,有些配置信息只有在應用集成這個Starter的時候才能明確。例如對於mybatis,configLocation、mapperLocation這些參數在每一個項目中均可能不一樣,因此只有應用本身知道這些參數的值該是什麼。mybatis-spring-boot-starter對外暴露了一組properties,例如若是咱們想指定mapper文件的存放位置,只須要在application.properties中添加mybatis.mapperLocations=classpath:mapping/*.xml便可。

下面咱們帶着這幾個問題,來看mybatis-spring-boot-starter是如何實現的。git

統一的dependency管理

這一點比較好理解,就是利用maven的間接依賴特性,在Starter的maven pom.xml中聲明全部須要的dependency,這樣在項目工程導入這個Starter時,相關的依賴就都被一塊兒導入了。下面是mybatis-spring-boot-starter的pom.xml,能夠看到與集成mybatis相關的dependency都已經聲明瞭。github

<project ...>
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot</artifactId>
        <version>2.0.1</version>
    </parent>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <name>mybatis-spring-boot-starter</name>
    <properties>
        <module.name>org.mybatis.spring.boot.starter</module.name>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-autoconfigure</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
        </dependency>
    </dependencies>
</project>

對外暴露properties

mybatis-spring-boot-autoconfigure模塊中的MybatisProperties類支持向外暴露相關的properties,它是經過@ConfigurationProperties實現的,並指定全部properties都以」mybatis「爲前綴。關於@ConfigurationProperties的具體用法可參考《Spring Boot外部化配置》
下面是MybatisProperties類的部分源碼:spring

@ConfigurationProperties(prefix = MybatisProperties.MYBATIS_PREFIX)
public class MybatisProperties {

  public static final String MYBATIS_PREFIX = "mybatis";

  private static final ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();

  /**
   * Location of MyBatis xml config file.
   */
  private String configLocation;

  /**
   * Locations of MyBatis mapper files.
   */
  private String[] mapperLocations;

  /**
   * Packages to search type aliases. (Package delimiters are ",; \t\n")
   */
  private String typeAliasesPackage;

  /**
   * The super class for filtering type alias. If this not specifies, the MyBatis deal as type alias all classes that
   * searched from typeAliasesPackage.
   */
  private Class<?> typeAliasesSuperType;

能夠看到,咱們使用mybatis的全部屬性均可以經過properties的形式在application.properties中配置。sql

實現自動裝配

自動裝配的原理已經在《Spring Boot自動裝配詳解》一問中介紹過。mybatis-spring-boot-autoconfigure模塊提供了兩個自動裝配類—— MybatisAutoConfigurationMybatisLanguageDriverAutoConfiguration,其中主要的配置功能是在MybatisAutoConfiguration中實現的,下面是MybatisAutoConfiguration類的部分源碼:segmentfault

@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties(MybatisProperties.class)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class })
public class MybatisAutoConfiguration implements InitializingBean {
  
...

  @Bean
  @ConditionalOnMissingBean
  public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
    SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
    factory.setDataSource(dataSource);
    factory.setVfs(SpringBootVFS.class);
    if (StringUtils.hasText(this.properties.getConfigLocation())) {
      factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
    }
    applyConfiguration(factory);
    if (this.properties.getConfigurationProperties() != null) {
      factory.setConfigurationProperties(this.properties.getConfigurationProperties());
    }
    if (!ObjectUtils.isEmpty(this.interceptors)) {
      factory.setPlugins(this.interceptors);
    }
    
    ...
    
  }

  ...

能夠看到,MybatisAutoConfiguration也是利用條件註解的方式構建各個須要的Bean,例如上面代碼片斷中建立的sqlSessionFactory Bean。
其中@AutoConfigureAfter註解在以前沒有說明過,它是一個hint註解,在這裏的做用是隻有當DataSourceAutoConfiguration和MybatisLanguageDriverAutoConfiguration這兩個自動裝配類執行完成後,再執行MybatisAutoConfiguration的自動裝配功能。mybatis

spring.factories

上面只是完成了AutoConfiguration類的編寫,那麼如何讓其在Spring Boot應用啓動時執行呢?
還記得EnableAutoConfiguration這個註解嗎?它是利用SpringFactoriesLoader機制加載全部的AutoConfiguration類的。因此咱們還須要將寫好的AutoConfiguration類放置到META-INF/spring.factories中。
在mybatis-spring-boot-autoconfigure模塊的META-INF/spring.factories文件中有下面配置代碼:app

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

這樣,在Spring Boot應用啓動時,就能夠加載並執行MybatisLanguageDriverAutoConfiguration和MybatisAutoConfiguration這兩個自動裝配類了。maven

總結

建立自定義的Spring Boot Starter並非什麼難事。經過對mybatis-spring-boot-starter的實現方式進行分析,能夠總結出下面建立自定義starter的步驟:spring-boot

  1. 確保在pom.xml文件中聲明瞭使用該組件所須要的所有dependency
  2. 利用@ConfigurationProperties註解對外暴露恰當的properties
  3. 利用條件註解@ConditionalXXX編寫XXXAutoConfiguration類
  4. 把寫好的XXXAutoConfiguration類加到META-INF/spring.factories文件的EnableAutoConfiguration配置中,這樣在應用啓動時就會自動加載並執行XXXAutoConfiguration。
相關文章
相關標籤/搜索