mysql embeded spring_spring boot自动配置之jdbc

1.DataSource配置

1.1 默认配置application.xml

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)

org.mybatis

mybatis

${mybatis.version}

org.mybatis

mybatis-spring

${mybatis-spring.version}

org.springframework.boot

spring-boot-starter-web

mysql

mysql-connector-java

com.zaxxer

HikariCP

tools

com.sun

2.自定义DataSource

1.1 application.xml配置文件

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配置

@Configurationpublic classSencondDataSourceConfiguration {

@Bean

@ConfigurationProperties(prefix= "spring.datasource")publicDataSource newDataSource() {returnDataSourceBuilder.create().build();

}

@Bean(name= "secondDatasource")

@ConfigurationProperties(prefix= "spring.second-datasource")publicDataSource secondDataSource() {returnDataSourceBuilder.create().build();

}

}

3.工作原理

spring boot的auto-configuration最具魔力的地方是@EnableAutoConfiguration注解

通常注解application应用使用@SpringBootApplication或者如下自定义的方式:

@Configuration

@EnableAutoConfiguration

@ComponentScanpublic classApplication

{

}

@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来分析一下:

/*** {@linkEnableAutoConfiguration Auto-configuration} for {@linkDataSource}.

*

*@authorDave Syer

*@authorPhillip Webb

*@authorStephane Nicoll

*@authorKazuki Shimizu*/@Configuration

@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class})

@EnableConfigurationProperties(DataSourceProperties.class)

@Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class})public classDataSourceAutoConfiguration {private static final Log logger =LogFactory

.getLog(DataSourceAutoConfiguration.class);

@Bean

@ConditionalOnMissingBeanpublicDataSourceInitializer dataSourceInitializer(DataSourceProperties properties,

ApplicationContext applicationContext) {return newDataSourceInitializer(properties, applicationContext);

}/*** Determines if the {@codedataSource} being used by Spring was created from

* {@linkEmbeddedDataSourceConfiguration}.

*@parambeanFactory the bean factory

*@returntrue if the data source was auto-configured.*/

public static booleancontainsAutoConfiguredDataSource(

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 classEmbeddedDatabaseConfiguration {

}

@Configuration

@Conditional(PooledDataSourceCondition.class)

@ConditionalOnMissingBean({ DataSource.class, XADataSource.class})

@Import({ DataSourceConfiguration.Tomcat.class, DataSourceConfiguration.Hikari.class,

DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class})protected static classPooledDataSourceConfiguration {

}

@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 classTomcatDataSourceJmxConfiguration {

@BeanpublicObject dataSourceMBean(DataSource dataSource) {if (dataSource instanceofDataSourceProxy) {try{return((DataSourceProxy) dataSource).createPool().getJmxPool();

}catch(SQLException ex) {

logger.warn("Cannot expose DataSource to JMX (could not connect)");

}

}return null;

}

}/*** {@linkAnyNestedCondition} that checks that either {@codespring.datasource.type}

* is set or {@linkPooledDataSourceAvailableCondition} applies.*/

static class PooledDataSourceCondition extendsAnyNestedCondition {

PooledDataSourceCondition() {super(ConfigurationPhase.PARSE_CONFIGURATION);

}

@ConditionalOnProperty(prefix= "spring.datasource", name = "type")static classExplicitType {

}

@Conditional(PooledDataSourceAvailableCondition.class)static classPooledDataSourceAvailable {

}

}/*** {@linkCondition} to test if a supported connection pool is available.*/

static class PooledDataSourceAvailableCondition extendsSpringBootCondition {

@OverridepublicConditionOutcome getMatchOutcome(ConditionContext context,

AnnotatedTypeMetadata metadata) {

ConditionMessage.Builder message=ConditionMessage

.forCondition("PooledDataSource");if (getDataSourceClassLoader(context) != null) {returnConditionOutcome

.match(message.foundExactly("supported DataSource"));

}returnConditionOutcome

.noMatch(message.didNotFind("supported DataSource").atAll());

}/*** Returns the class loader for the {@linkDataSource} class. Used to ensure that

* the driver class can actually be loaded by the data source.

*@paramcontext the condition context

*@returnthe class loader*/

privateClassLoader getDataSourceClassLoader(ConditionContext context) {

Class> dataSourceClass = newDataSourceBuilder(context.getClassLoader())

.findType();return (dataSourceClass == null ? null: dataSourceClass.getClassLoader());

}

}/*** {@linkCondition} to detect when an embedded {@linkDataSource} type can be used.

* If a pooled {@linkDataSource} is available, it will always be preferred to an

* {@codeEmbeddedDatabase}.*/

static class EmbeddedDatabaseCondition extendsSpringBootCondition {private final SpringBootCondition pooledCondition = newPooledDataSourceCondition();

@OverridepublicConditionOutcome getMatchOutcome(ConditionContext context,

AnnotatedTypeMetadata metadata) {

ConditionMessage.Builder message=ConditionMessage

.forCondition("EmbeddedDataSource");if (anyMatches(context, metadata, this.pooledCondition)) {returnConditionOutcome

.noMatch(message.foundExactly("supported pooled data source"));

}

EmbeddedDatabaseType type=EmbeddedDatabaseConnection

.get(context.getClassLoader()).getType();if (type == null) {returnConditionOutcome

.noMatch(message.didNotFind("embedded database").atAll());

}return ConditionOutcome.match(message.found("embedded database").items(type));

}

}/*** {@linkCondition} to detect when a {@linkDataSource} is available (either because

* the user provided one or because one will be auto-configured).*/@Order(Ordered.LOWEST_PRECEDENCE- 10)static class DataSourceAvailableCondition extendsSpringBootCondition {private final SpringBootCondition pooledCondition = newPooledDataSourceCondition();private final SpringBootCondition embeddedCondition = newEmbeddedDatabaseCondition();

@OverridepublicConditionOutcome getMatchOutcome(ConditionContext context,

AnnotatedTypeMetadata metadata) {

ConditionMessage.Builder message=ConditionMessage

.forCondition("DataSourceAvailable");if (hasBean(context, DataSource.class)|| hasBean(context, XADataSource.class)) {returnConditionOutcome

.match(message.foundExactly("existing data source bean"));

}if (anyMatches(context, metadata, this.pooledCondition,this.embeddedCondition)) {returnConditionOutcome.match(message

.foundExactly("existing auto-configured data source bean"));

}returnConditionOutcome

.noMatch(message.didNotFind("any existing data source bean").atAll());

}private boolean hasBean(ConditionContext context, Class>type) {returnBeanFactoryUtils.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 implementsBeanClassLoaderAware, EnvironmentAware, InitializingBean {public static final String PREFIX = "spring.datasource";

...

...privateString driverClassName;privateString url;privateString username;privateString 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值