首先,servlet3.0支持模块化,在jar包中如果有web-fragmenet.xml,则servlet容器会先加载web.xml里的listener、filter和servlet,再加载web-fragment.xml里的组件。关于模块化的介绍:
https://blog.csdn.net/chunxiaqiudong5/article/details/52840088
在javamelody-core中的META-INF目录下有一个web-fragment.xml文件,内容如下:
从上面文件中可以看出,当servlet容器启动时,会注册javamelody中定义的MonitoringFilter和SessionListener,MonitoringFilter默认的映射url为/monitoring。
此时我们想修改映射地址或者指定用户才能登录,有人在web.xml也配置了一个MonitoringFilter,如下:
启动servlet容器后,输入localhost:8080/xxx/admin,出现404,然后再输入localhost:8080/xxx/monitoring,发现javamelody的监控页面出来了。
为什么自己定义的/admin没有起作用,文章开头已经说了,servlet容器会先加载web.xml,然后是web-fragment.xml,但是这个又和加载顺序有什么关系了,难道说后加载的会覆盖先加载的配置吗,答案是yes。
点开MonitoringFilter源码,看下面一段代码:
在doFilter这个方面里,有一个getMonitoringUrl()的方法,这个方法是用来获取init-param中的配置的monitoring-path中的参数值,也就是映射url。如果请求地址和配置的monitoring-path路径一致,则会看到监控页面。刚才输入/admin无效,说明getMonitoringUrl()返回的并不是/admin,点进这个方法:
这里可以看出,paramterValue应该是我们配置的url,是从Parameters.getParameter()中获取的,Parameter是一个枚举,点进Parameters.getParameter()方法:
我们配置的url是从FilterConfig实例中取出来的,而FilterConfig是从哪里来的呢,在Filter实现类里重写了init(FilterConfig config)方法。
在这里,FilterConfig被注入,点进这个方法,
filterConfig为类变量,如果我们在web.xml里配置了MonitoringFilter,首先执行该MonitoringFIlter实例的init方法,然后再执行web-fragment.xml中MonitoringFilter实例的init()方法,所以Prameters类中的类变量FilterConfig总是后面web-fragment.xml配置的MonitoringFilter的FilterConfig。
解决办法:
在web.xml中定义一个MonitoringFilter,并将名字设为javamelody,与javamelody包中的一致。ServletContext不会加载同名的Filter,故web-fragment.xml中的MonitoringFilter不会添加,如下: