如何使用Spring的Java配置指定过滤器执行顺序?

8

我在我的初始化器中有以下代码:

public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Filter[] getServletFilters() {

        DelegatingFilterProxy shiroFilter = new DelegatingFilterProxy("shiroFilter");
        shiroFilter.setTargetFilterLifecycle(true);

        return new Filter[]{new CorsFilter(),shiroFilter};
    }
}

我希望在ShiroFilter之前执行CorsFilter。然而,Spring文档并没有说明过滤器执行的顺序是由它们在返回数组中的顺序决定的。
如果是这样,请有人澄清一下吗?如果不是,请有人建议如何确保过滤器的执行顺序?

在你的堆栈中,有一个名为OncePerRequestFilter的过滤器吗? - Sotirios Delimanolis
你是什么意思说“哪里”?它是Spring的一部分。 - pdeva
之前你提到了Shiro的OncePerRequestFilter,它是哪一个? - Sotirios Delimanolis
请阅读下面的评论。此评论应该放在帖子本身,而不是这里。 - pdeva
如果可以的话,在web.xml文件中过滤器的顺序是由您来决定的。 - Serge Ballesta
3个回答

14

仅为保持问题的最新状态。

使用 Spring @Order - Annotation

@Component(value = "myCorsFilter")
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {

    [...]

}

public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[] { AppConfiguration.class };
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return null;
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }

    @Override
    protected Filter[] getServletFilters() {
        return new Filter[] { 
             new DelegatingFilterProxy("myEncodingFilter"), 
             new DelegatingFilterProxy("myCorsFilter"),    // or just new CorsFilter()
             new DelegatingFilterProxy("mySecurityFilter") //...
        };
    }

}

6

过滤器在数组的顺序中注册。

这会导致ServletContext.addFilter()按照项目的顺序被调用,但是,我不确定这是否实际上会导致容器按照它们注册的顺序执行过滤器。

例如,Tomcat似乎使用HashMap来存储过滤器,因此我不希望过滤器一定按照添加的顺序运行。

Spring提供了一个org.springframework.web.filter.CompositeFilter,因此我建议返回一个包含您想要使用的两个过滤器的单个CompositeFilter


1
+1 我刚刚在研究如何使用CompositeFilter实现这个功能。创建一个DelegatingFilterProxy,它持有一个CompositeFilter,你可以向其中传递一个Filter bean列表来注册所需的过滤器。 - Sotirios Delimanolis
你能提供使用CompositeFilter转换后的代码示例吗?这将使得未来读者更容易理解。 - pdeva
显然,CompositeFilter 与使用 Apache Shiro 的 OncePerRequestFilter 的任何过滤器都不兼容,因为它的 OncePerRequestFilter.doFilter() 方法会检查该过滤器是否已经按名称执行,并且在这种情况下名称变成了“compositeFilter”(而不是执行过滤器),从而导致 OncePerRequestFilter 永远不会被执行。 - pdeva
2
看起来没有特别简单的方法可以做到这一点。这个答案建议由于Servlet API的限制,回归XML(https://dev59.com/wmw15IYBdhLWcg3whME1)。您还可以尝试将CompositeFilter包装在OncePerRequestFilter中。或者只需子类化ShiroFilter并直接调用CorsFilter。 - Phil Webb
2
Tomcat使用HashMap是一个误导:当在XML中声明时,Filter按正确顺序注册和执行,但通过注释发现和注册的Filter的顺序无法控制。为此,您必须使用web.xml或某种复合Filter - Christopher Schultz
显示剩余2条评论

0
对于可能想要使用javax注解而不是spring Order的人来说,也可以使用@javax.annotation.Priority注解来替代@Order,就像上面"dit"的回答一样。

最好将此作为对dit答案的评论。 - Roy Truelove

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接