Springboot
配置druid
数据连接池有两种方式,比较类似,但是如果搞混了容易导致部分配置不生效。
1.starter方式
这种比较简单
1.引入依赖
com.alibaba
druid-spring-boot-starter
1.1.20
2.添加属性
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url=jdbc:mysql://localhost:3306/workflow?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=workflow
spring.datasource.password=workflow
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
spring.datasource.druid.initial-size=1
spring.datasource.druid.max-active=20
spring.datasource.druid.min-idle=3
spring.datasource.druid.max-wait=60000
spring.datasource.druid.pool-prepared-statements=true
spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20
spring.datasource.druid.filters=stat,wall,slf4j
spring.datasource.druid.connection-properties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
这样启动项目就ok了。
注意,不需要自己添加新的数据连接池配置类DataSourceConfig
。添加了之后可能会导致项目启动失败或者部分属性例如maxActive
,minIdle
等这些不生效,具体原理下面会说。
3.原理
简单说下原理,这里用到了自动装配原理。
关键是这个类
@Configuration
@ConditionalOnClass({DruidDataSource.class})
@AutoConfigureBefore({DataSourceAutoConfiguration.class})
@EnableConfigurationProperties({DruidStatProperties.class, DataSourceProperties.class})
@Import({DruidSpringAopConfiguration.class, DruidStatViewServletConfiguration.class, DruidWebStatFilterConfiguration.class, DruidFilterConfiguration.class})
public class DruidDataSourceAutoConfigure {
private static final Logger LOGGER = LoggerFactory.getLogger(DruidDataSourceAutoConfigure.class);
public DruidDataSourceAutoConfigure() {
}
@Bean(
initMethod = "init"
)
@ConditionalOnMissingBean
public DataSource dataSource() {
LOGGER.info("Init DruidDataSource");
return new DruidDataSourceWrapper();
}
}
@Configuration
用于定义配置类,被注解的类内部包含有一个或多个被@Bean
注解的方法,这些方法将会被AnnotationConfigApplicationContext
或AnnotationConfigWebApplicationContext
类进行扫描,并用于构建bean定义,初始化Spring容器。
@ConditionalOnClass({DruidDataSource.class})
这段可以简单理解为只有当DruidDataSource.class
这个类存在时候才会实例化DruidDataSourceAutoConfigure
中定义的Bean。
@AutoConfigureBefore({DataSourceAutoConfiguration.class})
表示DruidDataSourceAutoConfigure
要在DataSourceAutoConfiguration
这个类之前加载。
@EnableConfigurationProperties({DruidStatProperties.class, DataSourceProperties.class})
表示开启自动装配属性,不需要手动set。与注解ConfigurationProperties
配合使用,ConfigurationProperties
负责将配置文件中的属性放到对象对应的属性中。
@Import({DruidSpringAopConfiguration.class, DruidStatViewServletConfiguration.class, DruidWebStatFilterConfiguration.class, DruidFilterConfiguration.class})
表示把用到的资源导入到IOC容器中。在这里就表示将这几个类实例化为Bean后加载到IOC容器中。不仅可以导入类,也可以通过@ImportResource
导入xml或者properties配置文件。
然后我们看类的实现,比较简单,除了构造方法只有一个方法public DataSource dataSource()
,这个方法就是返回一个数据库连接池Bean。包含了两个注解:
@Bean( initMethod = "init" )
表示返回一个Bean,同时在Bean初始化的时候要执行init
这个方法。
@ConditionalOnMissingBean
简单理解就是当dataSource
这个Bean不存在时候才会加载这个Bean。
返回的Bean很简单就是new了一个DruidDataSourceWrapper
对象。
接下来看下DruidDataSourceWrapper
这个类
@ConfigurationProperties("spring.datasource.druid")
class DruidDataSourceWrapper extends DruidDataSource implements InitializingBean {
@Autowired
private DataSourceProperties basicProperties;
DruidDataSourceWrapper() {
}
public void afterPropertiesSet() throws Exception {
if (super.getUsername() == null) {
super.setUsername(this.basicProperties.determineUsername());
}
if (super.getPassword() == null) {
super.setPassword(this.basicProperties.determinePassword());
}
if (super.getUrl() == null) {
super.setUrl(this.basicProperties.determineUrl());
}
if (super.getDriverClassName() == null) {
super.setDriverClassName(this.basicProperties.getDriverClassName());
}
}
@Autowired(
required = false
)
public void autoAddFilters(List filters) {
super.filters.addAll(filters);
}
public void setMaxEvictableIdleTimeMillis(long maxEvictableIdleTimeMillis) {
try {
super.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis);
} catch (IllegalArgumentException var4) {
super.maxEvictableIdleTimeMillis = maxEvictableIdleTimeMillis;
}
}
}
@ConfigurationProperties("spring.datasource.druid")
这个注解上面已经提到就是为了自动装配属性,装配哪些属性由括号里面的决定,这里是装配配置文件中spring.datasource.druid
开头的属性。看下之前的properties文件,发现主要是数据库连接池中maxActive
,minIdle
等这些属性。那么就会有个问题,连接池的最基础的属性url, username,password,driverClassName
这些在配置文件中不是以spring.datasource.druid
开头的,那么是怎么装配呢?有两种方法:
-
根据上面我们说的
@ConfigurationProperties("spring.datasource.druid")
可以装配以spring.datasource.druid
开头的属性,将properties文件中这几项的配置改为:spring.datasource.druid.url=jdbc:mysql://localhost:3306/workflow?useUnicode=true&characterEncoding=utf-8&useSSL=false spring.datasource.druid.username=workflow spring.datasource.druid.password=workflow spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
类似这样。这样
@ConfigurationProperties("spring.datasource.druid")
注解会将属性装配进来。 -
我们发现不修改也会装配进来,即下面这种形式也会装配进来
spring.datasource.url=jdbc:mysql://localhost:3306/workflow?useUnicode=true&characterEncoding=utf-8&useSSL=false spring.datasource.username=workflow spring.datasource.password=workflow spring.datasource.driver-class-name=com.mysql.jdbc.Driver
为什么会这样呢?
这与这个类
DruidDataSourceWrapper
里面的一个方法有关:afterPropertiesSet()
。
afterPropertiesSet
这个方法是InitializingBean
接口的实现,根据名称我们就可以猜到这个类和Bean的初始化有关系。这个方法会在Bean初始化的时候执行,并且是先于init
方法执行的。具体分析我们以后文章会分析,可以关注下。
afterPropertiesSet
这个方法我们看实现就是为了把url, username,password,driverClassName
这几个属性放到数据连接池对象中对应的属性。就是简单的set方法,我们看到这几个属性来自于DataSourceProperties
这个类的对象,那么这个类的对象从哪里获得连接的基本属性呢,看下类的实现:
@ConfigurationProperties(
prefix = "spring.datasource"
)
public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {
private ClassLoader classLoader;
private String name;
private boolean generateUniqueName;
private Class extends DataSource> type;
private String driverClassName;
private String url;
private String username;
private String password;
类太长,我们看关键部分。
这里还是用到了@ConfigurationProperties("spring.datasource")
这个注解,它负责把properties中spring.datasource
开头的属性装配到类DataSourceProperties
对象中对应的属性中。然后再通过afterPropertiesSet
方法放到DruidDataSourceWrapper
中对应的属性。
这样就会将所有的配置属性初始化到DataSource
Bean中。
这种配置Druid连接池方法中用到的最关键的技术就是Springboot的自动装配原理
2.非Starter方法
-
引入依赖
com.alibaba druid 1.1.9 -
添加属性
spring.datasource.druid.url=jdbc:mysql://localhost:3306/workflow?useUnicode=true&characterEncoding=utf-8&useSSL=false spring.datasource.druid.username=workflow spring.datasource.druid.password=workflow spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect spring.datasource.druid.initial-size=1 spring.datasource.druid.max-active=20 spring.datasource.druid.min-idle=3 spring.datasource.druid.max-wait=60000 spring.datasource.druid.pool-prepared-statements=true spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20 spring.datasource.druid.filters=stat,wall,slf4j spring.datasource.druid.connection-properties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
-
添加数据源配置类
public class DataSourceConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource.druid") public DataSource dataSource() { return new DruidDataSource(); } }
这里要注意配置properties文件中的
url, username,password,driverClassName
属性的写法,是包含“druid”的,因为这里也是用到了注解@ConfigurationProperties(prefix = "spring.datasource.druid")
来自动装配属性的,我们指定了自动装配以spring.datasource.druid
开头的属性,如果写成spring.datasource.url
则是没有办法自动装配的,属性不会生效。当然还有其他方法就是不使用自动装配,通过注解
@Value
获取到配置文件属性,然后手动用set方法将属性设置到DataSource对象对应的属性中去,这样比较麻烦,不推荐。