【发布时间】:2011-08-29 20:23:12
【问题描述】:
我的 Java 应用程序中有一个 servlet 过滤器,以确保用户使用最新的文章和类别 URI。问题是,根据分析器的结果,这个过滤器需要(自己)大约 40% 的请求总时间(即使是简单的 URI“/”)(内部操作是不平凡的,它的动态网页带有巨大的菜单,文章排名等)。
public class NameFilter implements Filter {
private ArticleServiceIface articleService;
private CategoryServiceIface categoryService;
private UrlRewriteServiceIface urlRewriteService;
private Pattern pattern = Pattern.compile("^(?>.*?)/(article|category)/(\\d+)/(?>.*)$");
public void init(FilterConfig filterConfig) throws ServletException {
ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(filterConfig.getServletContext());
articleService = (ArticleServiceIface) ctx.getBean("articleService");
categoryService = (CategoryServiceIface) ctx.getBean("categoryService");
urlRewriteService = (UrlRewriteServiceIface) ctx.getBean("urlRewriteService");
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
String uri = ((HttpServletRequest) request).getRequestURI();
Matcher matcher = pattern.matcher(uri);
String currUri;
if (matcher.matches()) {
if (matcher.group(1).equals("article")) {
Long articleId = Long.valueOf(matcher.group(2));
ArticleDTO a = articleService.getById(articleId);
currUri = urlRewriteService.getUrl(a.getId());
} else {
Long categoryId = Long.valueOf(matcher.group(2));
CategoryDTO c = categoryService.getById(categoryId);
currUri = urlRewriteService.getCategoryUrl(c.getId());
}
} else { //does not match neighter article nor category
chain.doFilter(request, response);
return;
}
if (currUri.equals(uri)) {
chain.doFilter(request, response);
} else {
HttpServletResponse res = (HttpServletResponse) response;
res.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
res.setHeader("Location", currUri);
res.getWriter().close();
}
}
public void destroy() {
}
}
我花了几个小时调试和分析它,尝试了许多不同的方法来制定正则表达式,但结果总是一样的。
瓶颈似乎在matches方法中,它被递归调用,在某些时候它出于某种原因迭代地调用模式匹配(几千次)......
感谢您的任何建议。
编辑:Profiler results(对我来说似乎很奇怪...根据调试器,这应该是解析 URI == "/" )
EDIT2:当前正则表达式:
private static Pattern pattern = Pattern.compile(".*?/(article|category)/(\\d+)/.*");
结果还是一样。我会尝试用
来衡量它 System.out.print(System.currTimeMillis - time)
EDIT3:结论:它可能是 netbeans profiler 错误...
我试过这段代码和URI“/”
long time = System.currentTimeMillis();
if (matcher.matches()) {
if (matcher.group(1).equals("article")) {
Long articleId = Long.valueOf(matcher.group(2));
ArticleDTO a = articleService.getById(articleId);
currUri = urlRewriteService.getUrl(a.getId());
} else {
Long categoryId = Long.valueOf(matcher.group(2));
CategoryDTO c = categoryService.getById(categoryId);
currUri = urlRewriteService.getCategoryUrl(c.getId());
}
} else { //does not match neighter article nor category
System.out.println(System.currentTimeMillis() - time);
....
输出始终为 0。因此在我看来,netbeans 分析器出于某种原因正在为该方法添加时间。
但是感谢大家的帮助和合作,我已经学会了一些正则表达式技巧。
【问题讨论】:
-
您能否提供一些需要很长时间的示例 URI?我针对
/尝试了您的模式,速度非常快。 -
打印 uri。是你想的那样吗?顺便说一句,你能解释一下有效的 url:s 是什么样的吗? /a/b/article/666/hello.txt 有效吗?
-
@ccoakley:在这个正则表达式
/(article|category)/(\\d+)/中,两个组都在捕获组,正如您在我的回答中看到的那样。要使它们成为非捕获组,请像这样使用它:/(?:article|category)/(?:\\d+)/ -
@ccoakley:我理解你的意思,但由于 OP 试图匹配 URIs
/en/article/123/articleName和/article/123/articleName因此[^/]*在这里不起作用。如果不是这样,我也会使用[^/]*,我认为它比.*?更好 -
@anubhava:谢谢。我的困惑实际上源于代码中组的原始编号(2,3 vs 1,2)。他们已经被纠正了(或者我疯了),这就是我认为事情应该是的样子。这就是为什么我被自己绊倒了。但是,是的,我的
[^/]*建议不好。