Druid是一个强大的新兴数据库连接池,兼容DBCP,是阿里巴巴做的开源项目.
不仅提供了强悍的数据源实现,还内置了一个比较靠谱的监控组件。
GitHub项目主页: https://github.com/alibaba/druid
QQ群: 点击链接加入群【阿里开源技术交流】
演示地址: http://cncounter.duapp.com/druid/index.html
常见问题回答请参考: https://github.com/alibaba/druid/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98
一篇CSDN对Druid的介绍 druid简单教程
因为想要监控数据,又不愿意谁都可以访问,所以想要配置个密码.在开源群里一问,就知道原来内部已经有实现了.
先贴完成后的代码:
web.xml 部分:
-
-
-
<filter>
-
<filter-name>DruidWebStatFilter</filter-name>
-
<filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class>
-
<init-param>
-
<param-name>exclusions</param-name>
-
<param-value>*.js,*.gif,*.jpg,*.png,*.css,*.ico,*.jsp,/druid/*,/download/*</param-value>
-
</init-param>
-
<init-param>
-
<param-name>sessionStatMaxCount</param-name>
-
<param-value>2000</param-value>
-
</init-param>
-
<init-param>
-
<param-name>sessionStatEnable</param-name>
-
<param-value>true</param-value>
-
</init-param>
-
<init-param>
-
<param-name>principalSessionName</param-name>
-
<param-value>session_user_key</param-value>
-
</init-param>
-
<init-param>
-
<param-name>profileEnable</param-name>
-
<param-value>true</param-value>
-
</init-param>
-
</filter>
-
<filter-mapping>
-
<filter-name>DruidWebStatFilter</filter-name>
-
<url-pattern>/*</url-pattern>
-
</filter-mapping>
-
-
<servlet>
-
<servlet-name>DruidStatView</servlet-name>
-
<servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
-
<init-param>
-
-
<param-name>resetEnable</param-name>
-
<param-value>true</param-value>
-
</init-param>
-
<init-param>
-
-
<param-name>loginUsername</param-name>
-
<param-value>druid</param-value>
-
</init-param>
-
<init-param>
-
-
<param-name>loginPassword</param-name>
-
<param-value>druid</param-value>
-
</init-param>
-
</servlet>
-
<servlet-mapping>
-
<servlet-name>DruidStatView</servlet-name>
-
<url-pattern>/druid/*</url-pattern>
-
</servlet-mapping>
下面分享一下如何查找的。
首先,因为使用的是 MAVEN, 所以查看源码时maven会自动帮你下载. 我们在 web.xml 中点击com.alibaba.druid.support.http.StatViewServlet 进入class文件,等一会源码下载好就可以查看. 发现有类似下面这样的代码:
-
public class StatViewServlet extends ResourceSerlvet {
-
-
private final static Log LOG = LogFactory.getLog(StatViewServlet.class);
-
-
private static final long serialVersionUID = 1L;
-
-
public static final String PARAM_NAME_RESET_ENABLE = "resetEnable";
-
-
public static final String PARAM_NAME_JMX_URL = "jmxUrl";
-
public static final String PARAM_NAME_JMX_USERNAME = "jmxUsername";
-
public static final String PARAM_NAME_JMX_PASSWORD = "jmxPassword";
-
-
private DruidStatService statService = DruidStatService.getInstance();
-
-
-
private String jmxUrl = null;
-
-
private String jmxUsername = null;
-
-
private String jmxPassword = null;
-
.........
可以看出,继承了StatViewServlet extends ResourceSerlvet
而在其中的 jmxUrl、jmxUsername 和 jmxPassword 很显然是连接远程 JMX时使用的,那么我就想着去看看父类: com.alibaba.druid.support.http.ResourceSerlvet
-
@SuppressWarnings("serial")
-
public abstract class ResourceSerlvet extends HttpServlet {
-
-
private final static Log LOG = LogFactory.getLog(ResourceSerlvet.class);
-
-
public static final String SESSION_USER_KEY = "druid-user";
-
public static final String PARAM_NAME_USERNAME = "loginUsername";
-
public static final String PARAM_NAME_PASSWORD = "loginPassword";
-
public static final String PARAM_NAME_ALLOW = "allow";
-
public static final String PARAM_NAME_DENY = "deny";
-
public static final String PARAM_REMOTE_ADDR = "remoteAddress";
-
-
protected String username = null;
-
protected String password = null;
-
..........
看到了 username 和 password,很高兴,先配置了试试,但是配置这两个初始化参数后没起作用,于是继续查找. 看到了 service方法,我们知道,Servlet的业务逻辑就是从这里开始的。
-
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
-
......
-
if (isRequireAuth()
-
&& !ContainsUser(request)
-
&& !("/login.html".equals(path)
-
|| path.startsWith("/css")
-
|| path.startsWith("/js")
-
|| path.startsWith("/img"))) {
-
if (contextPath == null || contextPath.equals("") || contextPath.equals("/")) {
-
response.sendRedirect("/druid/login.html");
-
} else {
-
if ("".equals(path)) {
-
response.sendRedirect("druid/login.html");
-
} else {
-
response.sendRedirect("login.html");
-
}
-
}
-
return;
-
}
-
......
发现调用了 isRequireAuth() 方法,看着像是判断是否需要授权验证,于是进去看
-
public boolean isRequireAuth() {
-
return this.username != null;
-
}
那现在知道是 username 在作怪,也设置了,但是没有起作用,于是搜索 username ,
-
public void init() throws ServletException {
-
initAuthEnv();
-
}
-
-
private void initAuthEnv() {
-
String paramUserName = getInitParameter(PARAM_NAME_USERNAME);
-
if (!StringUtils.isEmpty(paramUserName)) {
-
this.username = paramUserName;
-
}
-
-
String paramPassword = getInitParameter(PARAM_NAME_PASSWORD);
-
if (!StringUtils.isEmpty(paramPassword)) {
-
this.password = paramPassword;
-
}
-
......
然后发现了初始化验证环境时使用了PARAM_NAME_USERNAME这个参数,顺便的学习了一个新API: getInitParameter 方法获取 Servlet的初始化参数, 是HttpServlet的父类 GenericServlet 类提供的:
-
String paramUserName = getInitParameter(PARAM_NAME_USERNAME);
那么很简单,找到 PARAM_NAME_USERNAME 即可:
-
public static final String PARAM_NAME_USERNAME = "loginUsername";
-
public static final String PARAM_NAME_PASSWORD = "loginPassword";
于是在 web.xml 中换上,OK,成功进行了拦截.
https://github.com/alibaba/druid/wiki/DruidDataSource 配置属性列表
|
配置
|
缺省值
|
说明
|
|
name
|
|
配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开来。
如果没有配置,将会生成一个名字,格式是:"DataSource-" + System.identityHashCode(this)
|
|
jdbcUrl
|
|
连接数据库的url,不同数据库不一样。例如:
mysql : jdbc:mysql://10.20.153.104:3306/druid2
oracle : jdbc:oracle:thin:@10.20.149.85:1521:ocnauto
|
|
username
|
|
连接数据库的用户名
|
|
password
|
|
连接数据库的密码。如果你不希望密码直接写在配置文件中,可以使用ConfigFilter。详细看这里:https://github.com/alibaba/druid/wiki/%E4%BD%BF%E7%94%A8ConfigFilter
|
|
driverClassName
|
根据url自动识别
|
这一项可配可不配,如果不配置druid会根据url自动识别dbType,然后选择相应的driverClassName
|
|
initialSize
|
0
|
初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时
|
|
maxActive
|
8
|
最大连接池数量
|
|
maxIdle
|
8
|
已经不再使用,配置了也没效果
|
|
minIdle
|
|
最小连接池数量
|
|
maxWait
|
|
获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。
|
|
poolPreparedStatements
|
false
|
是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。
|
|
maxOpenPreparedStatements
|
-1
|
要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100
|
|
validationQuery
|
|
用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会其作用。
|
|
testOnBorrow
|
true
|
申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
|
|
testOnReturn
|
false
|
归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能
|
|
testWhileIdle
|
false
|
建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
|
|
timeBetweenEvictionRunsMillis
|
|
有两个含义:
1) Destroy线程会检测连接的间隔时间 2)
testWhileIdle的判断依据,详细看testWhileIdle属性的说明
|
|
numTestsPerEvictionRun
|
|
不再使用,一个DruidDataSource只支持一个EvictionRun
|
|
minEvictableIdleTimeMillis
|
|
|
|
connectionInitSqls
|
|
物理连接初始化的时候执行的sql
|
|
exceptionSorter
|
根据dbType自动识别
|
当数据库抛出一些不可恢复的异常时,抛弃连接
|
|
filters
|
|
属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有:
监控统计用的filter:stat 日志用的filter:log4j 防御sql注入的filter:wall
|
|
proxyFilters
|
|
类型是List<com.alibaba.druid.filter.Filter>,如果同时配置了filters和proxyFilters,是组合关系,并非替换关系
|
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/9399028/viewspace-1821979/
,如需转载,请注明出处,否则将追究法律责任。