1.DataSource配置java
1.1 默認配置application.xmlmysql
spring.datasource.url=jdbc:mysql://localhost/test spring.datasource.username=root spring.datasource.password=****
spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.type=com.zaxxer.hikari.HikariDataSource
須要在pom.xml加入依賴(我使用了mybatis+mysql)web
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>${mybatis.version}</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>${mybatis-spring.version}</version> </dependency> <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>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<exclusions>
<exclusion>
<artifactId>tools</artifactId>
<groupId>com.sun</groupId>
</exclusion>
</exclusions>
</dependency>spring
2.自定義DataSourcesql
1.1 application.xml配置文件apache
spring: application: name: data-multidatasource datasource: type: com.zaxxer.hikari.HikariDataSource url: jdbc:mysql://localhost:3306/test username: sa password: **** second-datasource: driver-class-name: org.hsqldb.jdbc.JDBCDriver url: jdbc:hsqldb:mem:db2 username: sa password:****
1.2 自定義DataSource配置tomcat
@Configuration public class SencondDataSourceConfiguration { @Bean @ConfigurationProperties(prefix = "spring.datasource") public DataSource newDataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "secondDatasource") @ConfigurationProperties(prefix = "spring.second-datasource") public DataSource secondDataSource() { return DataSourceBuilder.create().build(); } }
3.工做原理springboot
spring boot的auto-configuration最具魔力的地方是@EnableAutoConfiguration註解mybatis
一般註解application應用使用@SpringBootApplication或者以下自定義的方式:app
@Configuration @EnableAutoConfiguration @ComponentScan public class Application { }
@EnableAutoConfiguration註解開啓了spring ApplicationContext的自動配置功能,
它經過掃描classpath下的組件,知足不一樣Conditions的bean註冊到容器中。
spring boot提供了不一樣的AutoConfiguration實現類,這些類都在spring-boot-autoconfigure-{version}.jar中,用來註冊各類各樣的組件。
一般,當AutoConfiguration實現類打上@Configuration標籤,能夠做爲spring配置類,當AutoConfiguration實現類打上@EnableConfigurationProperties標籤,能夠綁定自定義屬性或者更多Conditional bean註冊方法。
下面就org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration來分析一下:
/** * {@link EnableAutoConfiguration Auto-configuration} for {@link DataSource}. * * @author Dave Syer * @author Phillip Webb * @author Stephane Nicoll * @author Kazuki Shimizu */ @Configuration @ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class }) @EnableConfigurationProperties(DataSourceProperties.class) @Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class }) public class DataSourceAutoConfiguration { private static final Log logger = LogFactory .getLog(DataSourceAutoConfiguration.class); @Bean @ConditionalOnMissingBean public DataSourceInitializer dataSourceInitializer(DataSourceProperties properties, ApplicationContext applicationContext) { return new DataSourceInitializer(properties, applicationContext); } /** * Determines if the {@code dataSource} being used by Spring was created from * {@link EmbeddedDataSourceConfiguration}. * @param beanFactory the bean factory * @return true if the data source was auto-configured. */ public static boolean containsAutoConfiguredDataSource( ConfigurableListableBeanFactory beanFactory) { try { BeanDefinition beanDefinition = beanFactory.getBeanDefinition("dataSource"); return EmbeddedDataSourceConfiguration.class.getName() .equals(beanDefinition.getFactoryBeanName()); } catch (NoSuchBeanDefinitionException ex) { return false; } } @Conditional(EmbeddedDatabaseCondition.class) @ConditionalOnMissingBean({ DataSource.class, XADataSource.class }) @Import(EmbeddedDataSourceConfiguration.class) protected static class EmbeddedDatabaseConfiguration { } @Configuration @Conditional(PooledDataSourceCondition.class) @ConditionalOnMissingBean({ DataSource.class, XADataSource.class }) @Import({ DataSourceConfiguration.Tomcat.class, DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class }) protected static class PooledDataSourceConfiguration { } @Configuration @ConditionalOnProperty(prefix = "spring.datasource", name = "jmx-enabled") @ConditionalOnClass(name = "org.apache.tomcat.jdbc.pool.DataSourceProxy") @Conditional(DataSourceAutoConfiguration.DataSourceAvailableCondition.class) @ConditionalOnMissingBean(name = "dataSourceMBean") protected static class TomcatDataSourceJmxConfiguration { @Bean public Object dataSourceMBean(DataSource dataSource) { if (dataSource instanceof DataSourceProxy) { try { return ((DataSourceProxy) dataSource).createPool().getJmxPool(); } catch (SQLException ex) { logger.warn("Cannot expose DataSource to JMX (could not connect)"); } } return null; } } /** * {@link AnyNestedCondition} that checks that either {@code spring.datasource.type} * is set or {@link PooledDataSourceAvailableCondition} applies. */ static class PooledDataSourceCondition extends AnyNestedCondition { PooledDataSourceCondition() { super(ConfigurationPhase.PARSE_CONFIGURATION); } @ConditionalOnProperty(prefix = "spring.datasource", name = "type") static class ExplicitType { } @Conditional(PooledDataSourceAvailableCondition.class) static class PooledDataSourceAvailable { } } /** * {@link Condition} to test if a supported connection pool is available. */ static class PooledDataSourceAvailableCondition extends SpringBootCondition { @Override public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { ConditionMessage.Builder message = ConditionMessage .forCondition("PooledDataSource"); if (getDataSourceClassLoader(context) != null) { return ConditionOutcome .match(message.foundExactly("supported DataSource")); } return ConditionOutcome .noMatch(message.didNotFind("supported DataSource").atAll()); } /** * Returns the class loader for the {@link DataSource} class. Used to ensure that * the driver class can actually be loaded by the data source. * @param context the condition context * @return the class loader */ private ClassLoader getDataSourceClassLoader(ConditionContext context) { Class<?> dataSourceClass = new DataSourceBuilder(context.getClassLoader()) .findType(); return (dataSourceClass == null ? null : dataSourceClass.getClassLoader()); } } /** * {@link Condition} to detect when an embedded {@link DataSource} type can be used. * If a pooled {@link DataSource} is available, it will always be preferred to an * {@code EmbeddedDatabase}. */ static class EmbeddedDatabaseCondition extends SpringBootCondition { private final SpringBootCondition pooledCondition = new PooledDataSourceCondition(); @Override public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { ConditionMessage.Builder message = ConditionMessage .forCondition("EmbeddedDataSource"); if (anyMatches(context, metadata, this.pooledCondition)) { return ConditionOutcome .noMatch(message.foundExactly("supported pooled data source")); } EmbeddedDatabaseType type = EmbeddedDatabaseConnection .get(context.getClassLoader()).getType(); if (type == null) { return ConditionOutcome .noMatch(message.didNotFind("embedded database").atAll()); } return ConditionOutcome.match(message.found("embedded database").items(type)); } } /** * {@link Condition} to detect when a {@link DataSource} is available (either because * the user provided one or because one will be auto-configured). */ @Order(Ordered.LOWEST_PRECEDENCE - 10) static class DataSourceAvailableCondition extends SpringBootCondition { private final SpringBootCondition pooledCondition = new PooledDataSourceCondition(); private final SpringBootCondition embeddedCondition = new EmbeddedDatabaseCondition(); @Override public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { ConditionMessage.Builder message = ConditionMessage .forCondition("DataSourceAvailable"); if (hasBean(context, DataSource.class) || hasBean(context, XADataSource.class)) { return ConditionOutcome .match(message.foundExactly("existing data source bean")); } if (anyMatches(context, metadata, this.pooledCondition, this.embeddedCondition)) { return ConditionOutcome.match(message .foundExactly("existing auto-configured data source bean")); } return ConditionOutcome .noMatch(message.didNotFind("any existing data source bean").atAll()); } private boolean hasBean(ConditionContext context, Class<?> type) { return BeanFactoryUtils.beanNamesForTypeIncludingAncestors( context.getBeanFactory(), type, true, false).length > 0; } } }
從上面看到,
1. DataSourceAutoConfiguration打上了@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })標籤,這意味着只有當DataSource.class和EmbeddedDatabaseType.class出如今classpath時,DataSourceAutoConfiguration內的自動配置bean纔可能被註冊。
2. DataSourceAutoConfiguration打上了@EnableConfigurationProperties(DataSourceProperties.class)標籤,意味着application.properties中的屬性和DataSourceProperties類自動綁定了。
@ConfigurationProperties(prefix = DataSourceProperties.PREFIX) public class DataSourceProperties implements BeanClassLoaderAware, EnvironmentAware, InitializingBean { public static final String PREFIX = "spring.datasource"; ... ... private String driverClassName; private String url; private String username; private String password; ... //setters and getters }
上面的配置類中說明,在application.properties中以spring.datasource開頭的屬性將自動綁定到DataSourceProperties對象上。其餘註解,如@ConditionalOnMissingBean, @ConditionalOnClass and @ConditionalOnProperty等,標識只要條件知足,bean definition將註冊到ApplicationContext中。
參考文件:
【1】http://www.liaoxuefeng.com/article/001484212576147b1f07dc0ab9147a1a97662a0bd270c20000
【2】https://dzone.com/articles/how-springboot-autoconfiguration-magic-works