今天在启动web应用的时候发现了一个问题,filter一直不生效,配置了spring的字符编码fitler,配置如下:
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<!--注意这里的配置-->
<url-pattern>/</url-pattern>
</filter-mapping>
注意上面的配置url-parrtern配置成”/“,后来我测试把/修改成/*就能成功,这就很奇怪了,激发了我强烈的兴趣。我把tomcat的源码通过maven的方式加入到了项目中,跟进到tomcat的源码看看到底是上面情况。可以查看项目中调试tomcat源码文章如何调试,发现了原因,先把tomcat对url-pattern的匹配源码贴出:
for (int i = 0; i < filterMaps.length; i++) {
if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
continue;
}
//根据requestPath匹配web.xml中配置的url
if (!matchFiltersURL(filterMaps[i], requestPath))
continue;
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMaps[i].getFilterName());
if (filterConfig == null) {
// FIXME - log configuration problem
continue;
}
boolean isCometFilter = false;
if (comet) {
try {
isCometFilter = filterConfig.getFilter() instanceof CometFilter;
} catch (Exception e) {
// Note: The try catch is there because getFilter has a lot of
// declared exceptions. However, the filter is allocated much
// earlier
Throwable t = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(t);
}
if (isCometFilter) {
filterChain.addFilter(filterConfig);
}
} else {
filterChain.addFilter(filterConfig);
}
}
在上面代码中matchFiltersURL(filterMaps[i], requestPath) 这行代码会根据每次请求找到对应需要执行的filter集合,构建ApplicationFilterConfig对象,将对象加入到我们属性的filterChain中。下面看一下matchFiltersURL源码:
private boolean matchFiltersURL(FilterMap filterMap, String requestPath) {
// Check the specific "*" special URL pattern, which also matches
// named dispatches
if (filterMap.getMatchAllUrlPatterns())
return (true);
if (requestPath == null)
return (false);
// Match on context relative request path
String[] testPaths = filterMap.getURLPatterns();
for (int i = 0; i < testPaths.length; i++) {
if (matchFiltersURL(testPaths[i], requestPath)) {
return (true);
}
}
// No match
return (false);
}
代码中根据web.xml配置的url-pattern存入到了filterMap对象中,调用matchFiltersURL(String testPath, String requestPath)比对是否匹配。
private boolean matchFiltersURL(String testPath, String requestPath) {
if (testPath == null)
return (false);
// Case 1 - Exact Match
if (testPath.equals(requestPath))
return (true);
// Case 2 - Path Match ("/.../*")
if (testPath.equals("/*"))
return (true);
if (testPath.endsWith("/*")) {
if (testPath.regionMatches(0, requestPath, 0,
testPath.length() - 2)) {
if (requestPath.length() == (testPath.length() - 2)) {
return (true);
} else if ('/' == requestPath.charAt(testPath.length() - 2)) {
return (true);
}
}
return (false);
}
// Case 3 - Extension Match
if (testPath.startsWith("*.")) {
int slash = requestPath.lastIndexOf('/');
int period = requestPath.lastIndexOf('.');
if ((slash >= 0) && (period > slash)
&& (period != requestPath.length() - 1)
&& ((requestPath.length() - period)
== (testPath.length() - 1))) {
return (testPath.regionMatches(2, requestPath, period + 1,
testPath.length() - 2));
}
}
// Case 4 - "Default" Match
return (false); // NOTE - Not relevant for selecting filters
}
上面是关键的匹配代码,我们发现没有单独的匹配/的代码逻辑,只有/*的逻辑,所以在web.xml中配置”/“是不生效的。
网友评论