德鲁伊简单使用
在翻阅项目底层代码时发现,在底层的framework
模块中有引入druid
监控端,但是好像在开发环境、测试环境甚至生产环境中并没有看到有具体的使用,所以想启用一下druid
的监控模块。并没有什么实质性内容的介绍,仅仅是踩的一些坑的记录。
注:我使用的版本是1.1.22
,如果不是这版本请绕道,避免引起不适,不同版本中修改了部分配置的前缀!!
启用德鲁伊管理页
1.根据配置项加载这个管理页bean
。前缀为my.druid.monitor.enable
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| @Bean("dataSource") @ConditionalOnMissingBean(DataSource.class) @ConfigurationProperties(prefix = "spring.datasource") public DataSource dataSource() { return DruidDataSourceBuilder.create().build(); }
@Bean @ConditionalOnProperty(prefix = "my.druid.monitor", name = "enable", havingValue = "true") public ServletRegistrationBean<StatViewServlet> druidServlet( @Value("${spring.datasource.druid.stat-view-servlet.login-password:admin}") String password, @Value("${spring.datasource.druid.stat-view-servlet.login-username:admin}") String userName, @Value("${spring.datasource.druid.stat-view-servlet.reset-enable:true}") String reset, @Value("${spring.datasource.druid.stat-view-servlet.url-pattern:/druid/*}") String urlPattern, @Value("${spring.datasource.druid.stat-view-servlet.allow:}") String allow, @Value("${spring.datasource.druid.stat-view-servlet.deny:}") String deny ) { ServletRegistrationBean<StatViewServlet> reg = new ServletRegistrationBean(); reg.setServlet(new StatViewServlet()); reg.addUrlMappings(urlPattern); reg.addInitParameter("resetEnable", reset); reg.addInitParameter("loginUsername", userName); reg.addInitParameter("loginPassword", password); reg.addInitParameter("allow",deny ); reg.addInitParameter("deny",allow); return reg; }
|
在yaml
或者properties
配置文件中添加相关配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| spring: autoconfigure: exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure datasource: druid: stat-view-servlet: enabled: true login-password: admin login-username: admin reset-enable: true url-pattern: /druid/* allow: deny:
dynamic: primary: master druid: filters: stat,wall initial-size: 10 max-active: 20 max-pool-prepared-statement-per-connection-size: 20 max-wait: 60000 min-evictable-idle-time-millis: 300000 min-idle: 10 pool-prepared-statements: true test-on-borrow: false test-on-return: false test-while-idle: true time-between-eviction-runs-millis: 60000 validation-query: SELECT 1 FROM DUAL connection-properties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000
|
到此在本地启动项目,访问http://127.0.0.1:8064/xxxx/druid/login.html
进入管理页,登录之后,虽然进入了管理页,但是其实只是一个空壳,执行对应的SQL
发现,并不会在监控页面上显示出来,后经过查询资料发现,这里的filter
为空。
在配置文件中明明在spring.datasource.druid.filters
设置了stat,wall
等过滤器,但是实际上没有读到,排查发现,在1.1.22
上,并不是这个配置,修改了配置前缀为spring.datasource.druid.filter.stat.enabled
具体代码:
1 2 3 4 5 6 7 8 9 10 11
| public class DruidFilterConfiguration {
@Bean @ConfigurationProperties(FILTER_STAT_PREFIX) @ConditionalOnProperty(prefix = FILTER_STAT_PREFIX, name = "enabled") @ConditionalOnMissingBean public StatFilter statFilter() { return new StatFilter(); } }
|
修改配置后,在启动项目,在管理页上就显示出了执行的SQL
语句。
开发环境启用
本以为到这里基本上已经万事大吉了,开发环境只需要复刻本地环境的配置即可。但是操作之后发现,在开发环境上访问login.html
之后原本应该跳转到druid/index.html
,但是404
,看样子是nginx
拦截处理了。
在nginx
中,对于/index.html
的路径直接转发到本地的某个文件夹中,所以修改nginx.conf
相关配置信息,是的对/druid/index.html
不进行这个拦截处理。
1 2 3 4 5 6 7 8 9 10 11
| location ~ .*/index.html { add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate"; root /opt/html; }
location ~ (?!.*druid/index.html$).*/index.html { add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate"; root /opt/html; }
|
重启nginx
之后,发现还是有问题,观察发送的请求,在login.html
提交表单之后,发起了一个submitLogin
请求,如果用户名密码校验正确,会直接跳转到druid/index.html
,但是这个druid/index.html
的请求居然进行了302
跳转,又跳回druid/login.html
页面。通过和本地的工程发起的请求对比发现,在submitLogin
登录之后会返回一个JSESSIONID
的cookies
,发起druid/index.html
请求需要携带这个cookies
值,但是在开发环境中不知道是nginx
还是哪里给弄丢了,由于时间紧迫我没有细看在那个环节丢调了这个cookies
值,我手动将这个cookies
值打入浏览器的cookies
中,正常访问。
关闭广告
在开源项目若依中看到,感觉挺好玩的,便记录一下,用过druid
管理页都知道,在面板的最下方有一个阿里的横幅广告,这个广告是请求服务器的common.js
中会添加到页脚,请求公网的banner
连接。
1 2 3 4 5 6 7 8 9
| buildFooter : function() {
var html ='<footer class="footer">'+ ' <div class="container">'+ '<a href="https://render.alipay.com/p/s/taobaonpm_click/druid_banner_click" target="new"><img src="https://render.alipay.com/p/s/taobaonpm_click/druid_banner"></a><br/>' + ' powered by <a href="https://github.com/alibaba/" target="_blank">Alibaba</a> & sandzhang & <a href="http://melin.iteye.com/" target="_blank">melin</a> & <a href="https://github.com/shrekwang" target="_blank">shrek.wang</a>'+ ' </div>'+ ' </footer>'; $(document.body).append(html);
|
所以思路上,通过对获取common.js
进行拦截,并将这段页脚的html
代码重写,即可达到关闭广告的目的。
1.设置一个过滤器,对js/common.js
的请求进行拦截。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @Configuration public class DruidConfig {
@Bean @ConditionalOnProperty(prefix = "my.druid.monitor", name = "enable", havingValue = "true") public FilterRegistrationBean<DruidAdRemoveFilter> druidAdRemoveFilterFilter(DruidStatProperties properties) { DruidStatProperties.StatViewServlet config = properties.getStatViewServlet(); String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*"; String commonJsPattern = pattern.replaceAll("\\*", "js/common.js");
FilterRegistrationBean<DruidAdRemoveFilter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new DruidAdRemoveFilter()); registrationBean.addUrlPatterns(commonJsPattern); return registrationBean; } }
|
2.拦截过滤器中替换这段html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class DruidAdRemoveFilter extends OncePerRequestFilter {
private static final String COMMON_JS_ILE_PATH = "support/http/resources/js/common.js";
@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { chain.doFilter(request, response); response.resetBuffer(); String text = Utils.readFromResource(COMMON_JS_ILE_PATH); text = text.replaceAll("<a.*?banner\"></a><br/>", ""); text = text.replaceAll("powered.*?shrek.wang</a>", ""); response.getWriter().write(text); } }
|
替换之后的html
变量值为:
1 2 3 4 5 6
| var html ='<footer class="footer">'+ ' <div class="container">'+ '' + ' '+ ' </div>'+ ' </footer>';
|