什么是druid?
Druid是阿里开源的数据库连接池项目,它还包含一个ProxyDriver,一系列内置的JDBC组件库,一个SQLParser。Druid支持所有JDBC兼容的数据库,包括Oracle、MySql、Derby、Postgresql、SQLServer、H2等等。
在我们的微服务项目中,可以使用druid来进行数据库连接,并且在druid中内置了SQl监控和URL访问监控,可以实时的监控程序的稳定性。
源码分析:
我们是使用SprongBoot来架构项目,所以我们导入druid-spring-boot-starter依赖,这样在项目中就存在自动配置类来获取配置:
首先获取数据源
com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
@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);
@Bean(initMethod = "init")
@ConditionalOnMissingBean
public DataSource dataSource() {
LOGGER.info("Init DruidDataSource");
return new DruidDataSourceWrapper();
}
}
可以看到在这里需要获取数据源信息,调用DruidDataSourceWrapper这个类中加载属性的方法来配置druid
@ConfigurationProperties("spring.datasource.druid")
class DruidDataSourceWrapper extends DruidDataSource implements InitializingBean {
@Autowired
private DataSourceProperties basicProperties;
这里我们注入了DataSourceProperties 这个类来加载属性
@ConfigurationProperties("spring.datasource.druid")
public class DruidStatProperties {
private String[] aopPatterns;
private StatViewServlet statViewServlet = new StatViewServlet();
private WebStatFilter webStatFilter = new WebStatFilter();
在父类中的获取连接的方法getConnection
@Override
public DruidPooledConnection getConnection() throws SQLException {
return getConnection(maxWait);
}
public DruidPooledConnection getConnection(long maxWaitMillis) throws SQLException {
init();
if (filters.size() > 0) {
FilterChainImpl filterChain = new FilterChainImpl(this);
return filterChain.dataSource_connect(this, maxWaitMillis);
} else {
return getConnectionDirect(maxWaitMillis);
}
}
首先调用init()方法来加载关于数据源的信息,具体参见对应方法
如果我们没有配置的Filter时,我们调用getConnectionDirect这个方法,但是我们使用SQl监控时,需要使用filterChain.dataSource_connect方法获取数据库连接。
protected int pos = 0;
@Override
public DruidPooledConnection dataSource_connect(DruidDataSource dataSource, long maxWaitMillis) throws SQLException {
if (this.pos < filterSize) {
DruidPooledConnection conn = nextFilter().dataSource_getConnection(this, dataSource, maxWaitMillis);
return conn;
}
return dataSource.getConnectionDirect(maxWaitMillis);
}
private Filter nextFilter() {
return getFilters()
.get(pos++);
}
在这里通过过滤器链进行配置数据库监控,直到最后一个过滤器执行后,执行获取数据库连接的方法
public DruidPooledConnection getConnectionDirect(long maxWaitMillis) throws SQLException {}
通过getConnectionDirect方法获取数据库连接池
这个方法中主要就是根据我们在配置文件中的配置来获取数据库连接
下面是获取连接时需要的属性:
- testOnBorrow 在申请连接时监测连接的可用性,开启会降低性能
- testWhileIdle 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
- removeAbandone 是否开启自动清理被租借的连接但是又没有还回线程池,开启会影响性能
怎么使用druid?
首先,我们需要导入对应的依赖
我们使用SpringBoot项目进行架构,我们导入
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
导入依赖后,我们需要在配置文件中进行配置,在application.yml中添加配置
#配置数据库
spring:
datasource:
name: test
url: jdbc:mysql://localhost:3306/data?characterEncoding=utf-8&serverTimezone=UTC&useSSL=false
username: root
password: root
#配置druid数据库连接
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
filters: stat
maxActive: 20
initialSize: 1
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20
使用这些配置后,我们可以使用数据库连接池的功能,但是若使用SQl监控的功能,我们需要进行配置过滤器
@WebServlet(urlPatterns = "/druid/*",
initParams={
@WebInitParam(name="allow",value=""),// IP白名单 (没有配置或者为空,则允许所有访问)
@WebInitParam(name="deny",value="192.168.0.1"),// IP黑名单 (存在共同时,deny优先于allow)
@WebInitParam(name="loginUsername",value="root"),// 用户名
@WebInitParam(name="loginPassword",value="root"),// 密码
@WebInitParam(name="resetEnable",value="false")// 禁用HTML页面上的“Reset All”功能
})
@WebFilter(filterName="myFilter",urlPatterns="/*")
public class MyFilter extends StatViewServlet implements Filter {
/**
*/
private static final long serialVersionUID = 1L;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
System.out.println(request.getRequestURI());
HttpServletResponse response = (HttpServletResponse) servletResponse;
filterChain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
然后在启动类中开启注解扫描
@ServletComponentScan