当一个web项目启动的时候,web容器会去读取配置文件web.xml.web.xml 中可以配置lisenter,context-param,servlet,filter 等。
而当配置filter的时候,可以给filter配置一些初始化参数。这时候假如有两个filter 拥有共同的初始化参数时,那怎么办呢?是初始化两次?每个filter的参数值都是一样的,这样肯定不好。如果其中一个filter(A)能够把初始化参数传给另一个filter(B)就行了。
方法1 :
每个filter都有 doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) 方法。如果我能够在filter A 的 doFilter方法中 把初始化的参数放到request对象中,然后filter B 从request 中取就行了。 想想理论上是可行的,但是fitler A 是j组件ar 包里面的文件,不能修改。失败!
方法2 :
servletContext接口是Servlet中最大的一个接口,呈现了web应用的Servlet视图。存有上下问信息。各web容器会实现该接口 。但是根据API该接口貌似不存在getFilter类似的方法。tomncat实现的接口对象时ApplicationContextFacade 。 通过伟大的debug会发现 ApplicationContextFacade中的ApplicationContext中的StandardContext对象会有获取filter的方法findFilterConfig()。 所以我们只需要得到ApplicationContext对象就行了。由于ApplicationContext对象没有提供公用的方法供调用,这时一个强大的java工具就出现了:反射!。 下面贴出代码供参考。
public void init(FilterConfig filterConfig) throws ServletException {
this.isOn = Boolean.valueOf(filterConfig.getInitParameter("isOn"));
ApplicationContextFacade facade = (ApplicationContextFacade) filterConfig.getServletContext();
try {
Field field = facade.getClass().getDeclaredField("context");
field.setAccessible(true);
ApplicationContext context = (ApplicationContext) field.get(facade);
Method method = context.getClass().getDeclaredMethod("getContext");
method.setAccessible(true);
StandardContext sContext = (StandardContext) method.invoke(context, new Object[]{});
FilterConfig casFilterConfig= sContext.findFilterConfig("casFilter");
//单点登陆服务器不验证的东西 ,我们也不验证。 特别的是把退出的操作包含进来.
excludeURL = FilterUtils.getExcludeURL(casFilterConfig);
String logoutURL = casFilterConfig.getInitParameter("logoutUrl");
String[] newArray = new String[excludeURL.length+1];
System.arraycopy(excludeURL, 0, newArray, 0, excludeURL.length);
newArray[newArray.length-1] = logoutURL;
excludeURL = newArray;
} catch (Exception e) {
logger.error("过滤器反射获取失败", e);
}
PS:这样的话还需要保证web.xml 文件中filter A要在filterB前面(filter-mapping 的配置),否则可能会出现获取不到值的情况。