本篇主要來讨論研究兩個問題:1、什麼自動配置,2、如何編寫自動配置
在使用 Spring 作為項目開發架構的過程中,當需要內建某個元件時,通常需要大量的 xml 配置才可以讓項目工程 run 起來,下面先以 mybatis 為例,來看下如何使用 mybatis-Spring 子產品,需要哪些必不可少的依賴和配置。
使用 mybatis-spring
任何元件的內建都繞不過兩個問題:依賴和配置,關于配置在[]()這篇文章中介紹了配置的一些點,有興趣的可以看下。
依賴
從 mybatis 的官方文當可以了解到,要使用 MyBatis-Spring 子產品,需要在類路徑下包含 mybatis-spring.jar 檔案和相關依賴(如:mysql-connector-java)即可。如果使用 Maven 作為建構工具,則在 pom.xml 中加入以下代碼即可:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${latest.version}</version>
</dependency>
複制
bean 配置
Spirng 內建 mybatis 通常需要以下 bean 配置:
1、dataSource
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
// 省略其他配置
</bean>
複制
2、sqlSessionFactory
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
複制
3、其他:包掃描事務配置
<!-- DAO 接口所在包名,Spring 會自動查找其下的類,并将其定義為一個 Spring Bean -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.glmapper.bridge.boot.dao" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
<!-- (事務管理)transaction manager -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
複制
這些個 bean 是在 Spring 中使用 mybatis 架構時基本必不可少的配置。那麼在 SpringBoot 中呢?
SpringBoot 中如何內建 mybatis 的
SpringBoot 內建 mybatis 非常簡單,加一下下面的 starter ,再在 application.properties 配置下資料庫連接配接配置即可;不需要配置 datasource,sqlSessionFactory 等這些 bean。
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
複制
官方文檔:https://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/
mybatis starter 是如何規避 bean 配置的
引用
mybatis-spring-boot-starter
既然可以不用在 xml 中配置 bean ,那肯定是這些 bean 是在
mybatis-spring-boot-starter
中通過某種方式被建立了。
在 SpringBoot 官方文檔的描述中,starter 隻是用來管理依賴的,一般不會有代碼,自動配置的代碼一般在中。mybatis 的自動配置相關代碼是在
xxxx-autoconfigure
中。
mybatis-spring-boot-autoconfigure
mybatis-spring-boot-autoconfigure
這依賴中隻有簡單的幾個類,其中最核心的就是 MybatisAutoConfiguration 這個配置類。另外一個 MybatisProperties 是 mybatis spring boot 的屬性配置類,就是常見的 mybatis.xxxx。
MybatisAutoConfiguration 自動配置類
MybatisAutoConfiguration 的定義及其生效條件:
- 1.目前 classpath 下必須有 SqlSessionFactory 和 SqlSessionFactoryBean 這兩個類
- 2.存在 DataSource bean 執行個體
- 3.有配置類 MybatisProperties 執行個體
-
4.在 DataSourceAutoConfiguration 和 MybatisLanguageDriverAutoConfiguration 兩個自動配置類之後重新整理
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class }) @ConditionalOnSingleCandidate(DataSource.class) @EnableConfigurationProperties(MybatisProperties.class) @AutoConfigureAfter({ DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class }) public class MybatisAutoConfiguration implements InitializingBean { // 定義 SqlSessionFactory bean @Bean @ConditionalOnMissingBean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { // } // check @Override public void afterPropertiesSet() { checkConfigFileExists(); } // 省略其他code }
從上面的代碼片段大體可以知道 MybatisAutoConfiguration 所做的事情主要包括以下幾點:1、重新整理 SqlSessionFactory 和 SqlSessionFactoryBean 兩個 bean;2、afterPropertiesSet 中做一些準備或者檢驗工作(這裡就是 check 了 mybatis 的配置檔案是否配置了)
關于 DataSource 的 bean ,則是由 DataSourceAutoConfiguration 這個配置類中來定義。
具體代碼有興趣的讀者可以自己查閱相關源碼,這裡就不展開了。
是以整體看來, MybatisAutoConfiguration 及其所依賴的 xxxConfiguration 會幫助使用者定義 bean 和解析配置。
mybatis 自動配置的 bean 是如何生效的
上面分析到 MybatisAutoConfiguration 及其依賴的配置自動類會幫助建立運作時所需要的 bean,那麼這些 bean 是如何被 SpringBoot 架構感覺并加載的呢?
其實一般的項目工程中,如果我們在一個類上打了 @Configuration 注解的話,Spring 會直接能夠加載到的(前提是這個類所在的包在啟動類的子包下)。但是在架構層面,項目的包和所引入的元件包的包路徑肯定是有差異的,是以在一些情況下會刷不到依賴中的 bean。
SpringBoot 中提供了一種類似于 SPI 機制的方式來幫忙加載 EnableAutoConfiguration、ApplicationListner、ApplicationContextInitializer 等類型的 bean。比如 mybatis 自動配置的配置如下:
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
複制
其處理邏輯在 SpringApplication 類中,具體解析方法如下:
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
ClassLoader classLoader, Object[] args, Set<String> names) {
List<T> instances = new ArrayList<>(names.size());
for (String name : names) {
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
// 反射拿到構造函數
Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
// 建立 bean
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
}
catch (Throwable ex) {
throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
複制
如何編寫自己的 starter
本小節将結合上面的描述,自定義一個 starter,讓你的項目和 xml bean 配置說再見。
場景描述:有兩個 bean,一個 parentBean,一個 childBean,parentBean 需要依賴 childBean,parentBean中又要依賴 http 包
原來的 xml 配置:
<bean id="parentBean" class="com.glmapper.bridge.boot.service.impl.ParentBean">
<property name="childBean" ref="childBean"></property>
</bean>
<bean id="childBean" class="com.glmapper.bridge.boot.service.impl.ChildBean"/>
複制
下面考慮的是将這些 bean 作為公共元件提供給其他項目工程用,從架構角度來看,最佳實踐是:
- 提供一個 autoconfigure 子產品用于編寫自動配置類代碼
- 提供一個 starter,用于提供給外部使用者使用
編寫 autoconfigure
-
自動配置類
@Configuration // parentBean 依賴 HttpClient,是以如果沒有 HttpClient 則不會重新整理目前自動配置類 @ConditionalOnClass(HttpClient.class) public class GlmpperAutoConfiguration { // ParentBean bean 定義 @Bean @ConditionalOnMissingBean // 如果目前 Spring 容器中已經存在 parentBean則不會再建立 public ParentBean parentBean(){ return new ParentBean(); } // ChildBean bean 定義 @Bean @ConditionalOnMissingBean public ChildBean childBean(){ return new ChildBean(); } }
- 依賴 scope 使用 provided,不直接打在 autoconfigure 依賴中
<dependencies>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.6</version>
<scope>provided</scope>
</dependency>
</dependencies>
複制
- 編寫 spring.factories,在 resources/META-INF/ 建立一個 spring.factories 檔案,配置如下:

編寫 starter
starter 裡面沒有代碼,隻做依賴管控
<dependency>
<groupId>com.glmapper.bridge.boot</groupId>
<artifactId>guides-autoconfigure</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.6</version>
</dependency>
複制
starter 裡面包括了自動配置的依賴和 httpclient 的依賴,是以使用者在引入 starter 之後所有生效條件都滿足了,就會在啟動時直接重新整理。
示例工程: https://github.com/glmapper/springboot-series-guides.git(guides-autoconfigure 子產品和 guides-starter 子產品)
小結
本篇是介于源碼解析和實踐系列之間的一篇,作為源碼解析的終篇和實踐的開篇。
本篇以 mybatis 為例,對 spring 環境和 SpringBoot 環境下的使用方式做了簡單對比;以此為切入點,介紹了 SpringBoot 中的自動配置及 starter 最佳實踐。
溫馨提示
源碼解析課程告以段落,接下來将進入實戰課程了,大家敬請期待!
▐ 文章來源:磊叔授權分享,轉載請先聯系原作者,謝謝!