代碼示例:https://git.oschina.net/null_584_3382/spring-boot-introductionjava
在介紹spring boot 自動配置原理以前,先看一個例子,spring boot集成mybatis,mysql
測試用的數據庫爲mysql,因此引入mysql-connector-java依賴git
引入myatis提供的mybatis-spring-boot-starterweb
最後引入druid鏈接池依賴spring
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.1.1</version> </dependency> <!-- https://mvnrepository.com/artifact/com.alibaba/druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>RELEASE</version> </dependency> </dependencies>
按照mvc邏輯,首先是controller,很普通的代碼sql
@RestController public class Controller { @Autowired DemoMapper demoMapper; @RequestMapping("/fetchByName") public Object fetchByName(@RequestParam("name") String name){ return demoMapper.fetchByName(name); } }
由於只是一個例子,因此省略server層,直接使用dao層數據庫
@Mapper public interface DemoMapper { @Select("select * from userinfo where name=#{name}") UserInfo fetchByName(String name); }
嗯,代碼都是很普通的,可是datasource是在哪裏配置的呢?springboot
關鍵就在配置文件mybatis
spring: datasource: url: jdbc:mysql://${url}:3306/bootintro username: root password: ${password} driver-class-name: com.mysql.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource
好了,全部關鍵代碼都在這裏了(哦,還有Application類和domain類,省略了),運行一下(固然,你還要配置本身的數據庫)mvc
沒錯,前面說過,spring boot爲咱們提供了自動配置,那自動配置的怎麼作到的。
spring boot中有不少類的名字爲***AutoConfiguration,這些類都是一些spring的配置類(頭上有@Configuration),就是這些類提供了一些默認配置,若是你使用spring基於java的配置,其實也是作了一樣的事情,只不過springboot幫咱們作!!
恩,你確定會接着問,那麼spring boot怎麼知道有哪些類是所謂的"***AutoConfiguration"。@EnableAutoConfiguration,就是這個註解開啓了自動配置,這個註解包括:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(EnableAutoConfigurationImportSelector.class)
其中主要的是EnableAutoConfigurationImportSelector這個類,就是用來選擇哪些是須要自動配置的。這個類的核心代碼:
@Override public String[] selectImports(AnnotationMetadata metadata) { if (!isEnabled(metadata)) { return NO_IMPORTS; } try { AnnotationAttributes attributes = getAttributes(metadata); List<String> configurations = getCandidateConfigurations(metadata, attributes); configurations = removeDuplicates(configurations); Set<String> exclusions = getExclusions(metadata, attributes); configurations.removeAll(exclusions); configurations = sort(configurations); recordWithConditionEvaluationReport(configurations, exclusions); return configurations.toArray(new String[configurations.size()]); } catch (IOException ex) { throw new IllegalStateException(ex); } }
其中的最關鍵的是getCandidateConfigurations()這個方法中的:
List<String> configurations = SpringFactoriesLoader.loadFactoryNames( getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
追蹤進去看就能夠發現,這類就是在全部的classpath下查找META-INF/spring.factories這個文件,從這個文件中提出key爲org.springframework.boot.autoconfigure.EnableAutoConfiguration的值,而這些值就是一些自動配置類
例如,mybatis提供的META-INF/spring.factories內容:
# Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
多說2句:
@Override protected String[] selectImports(AdviceMode adviceMode) { switch (adviceMode) { case PROXY: return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()}; case ASPECTJ: return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME}; default: return null; } }
非也,仔細看某個***AutoConfig,舉個例子,例如自動配置http編碼的CharacterEncodingFilter的自動配置類HttpEncodingAutoConfiguration:
@Configuration @EnableConfigurationProperties(HttpEncodingProperties.class) @ConditionalOnWebApplication @ConditionalOnClass(CharacterEncodingFilter.class) @ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true) public class HttpEncodingAutoConfiguration { private final HttpEncodingProperties properties; public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) { this.properties = properties; } @Bean @ConditionalOnMissingBean(CharacterEncodingFilter.class) public CharacterEncodingFilter characterEncodingFilter() { CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter(); filter.setEncoding(this.properties.getCharset().name()); filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST)); filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE)); return filter; } ... ... }
其中,註解中包括許多@Confitionalxxx的,就是這些註解來控制該自動配置是否生效,根據這些註解名字大概都能知道是什麼意思,例如@ConditionalOnWebApplication,這個確定就是隻有在web工程中才知足,@ConditionalOnClass只有存在CharacterEncodingFilter.class這個類的時候纔有效。
spring boot中的大多數自定義配置均可以經過修改配置來完成,例如,仍是上面的那個例子,其中有個註解@EnableConfigurationProperties(HttpEncodingProperties.class),而HttpEncodingProperties類就是讀取配置文件信息,所以,經過修改配置信息,自動配置類生效的時候就會按照配置信息來自動配置。例如,DataSourceAutoConfiguration,加載配置文件的類爲
@ConfigurationProperties(prefix = "spring.datasource") public class DataSourceProperties implements BeanClassLoaderAware, EnvironmentAware, InitializingBean { ... /** * Fully qualified name of the JDBC driver. Auto-detected based on the URL by default. */ private String driverClassName; /** * JDBC url of the database. */ private String url; /** * Login user of the database. */ private String username; /** * Login password of the database. */ private String password; ... }
能夠知道,在spring boot的配置文件中查找配置屬性,根據配置屬性來填充該類的屬性值
多說2句
代碼示例:https://git.oschina.net/null_584_3382/spring-boot-introduction