Spring MVC 的委派过滤器代理有什么意义?

我在我的 Spring MVC 应用程序的 web.xml中看到了这一点:

<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

我想弄清楚为什么它会在那里,是否真的需要它。

我找到了 Spring 文档中的这个解释,但它并没有帮助我理解它:

这似乎表明这个组件是 web.xml中定义的 servlet 和 Spring applicationContext.xml中定义的组件之间的“粘合剂”。

7.1 DelegatingFilterProxy

在使用 servlet 过滤器时,显然需要在 web.xml中声明它们,否则 servlet 容器将忽略它们。在 Spring Security 中,过滤器类也是在应用程序上下文中定义的 Spring bean,因此能够利用 Spring 丰富的依赖注入设施和生命周期接口。Spring 的 DelegatingFilterProxy提供了 web.xml和应用程序上下文之间的链接。

在使用 RegiatingFilterProxy 时,您将在 web.xml文件中看到类似的内容:

<filter>
<filter-name>myFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>


<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

注意,过滤器实际上是一个 DelegatingFilterProxy,而不是实际实现过滤器逻辑的类。DelegatingFilterProxy所做的是将 Filter 的方法委托给从 Spring 应用程序上下文获取的 bean。这使得 bean 能够受益于 Springweb 应用程序上下文生命周期支持和配置灵活性。Bean 必须实现 javax.servlet.Filter,并且它的名称必须与 filter-name 元素中的名称相同。阅读 用于委托 FilterProxy 的 Javadoc以获得更多信息

那么,如果我把这个从 web.xml中取出,会发生什么?我的 servlet 将无法与 Spring 容器通信?**

79915 次浏览

关于“粘合”的东西你是对的,正如在 FilterChainProxy的 JavaDocs 中所写的:

FilterChainProxy 通过在应用程序 web.xml 文件中添加一个标准的 Spring GeneratingFilterProxy 声明链接到 servlet 容器过滤器链中。

请参阅博客 Spring 安全命名空间背后的 FIlterChainProxy 部分以获得更好的解释。

你知道什么是 Servlet 过滤器以及它是如何工作的吗?它是 Servlet 规范中非常有用的一部分,允许我们将类似 AOP 的概念应用于 HTTP 请求服务。许多框架使用 Filter 实现做各种事情,找到它们的自定义实现并不罕见,因为它们编写起来非常简单,而且非常有用。在 Spring 应用程序中,应用程序可以做的大部分事情都在 Spring bean 中。但是 Filter 实例是由 Servlet 容器控制的。容器实例化、初始化并销毁它。Servlet Spec 不需要任何类型的 Spring 集成,所以只剩下一个非常有用的概念(Filters) ,没有方便的方法将它与 Spring 应用程序和执行工作的 bean 绑定在一起。

Enter the DelegatingFilterProxy. You write a Filter implementation and make it a Spring bean, but instead of adding your own Filter class to the web.xml, you use the DelegatingFilterProxy, and give it the bean name of your filter in the Spring context. (If you don't explicitly provide a name, it uses the "filter-name".) Then at runtime, the DelegatingFilterProxy handles the complexity of finding the real implementation - the one you wrote and configured in Spring - and routing requests to it. So at runtime, it's as if you had listed your filter in the web.xml, but you get the benefit of being able to wire it like any other Spring bean.

如果您将过滤器映射从 web.xml 中取出,那么一切都将继续工作,但是您的 URL 都不会受到保护。(假设名称“ springSecurityFilterChain”准确地描述了它的功能。)这是因为这个映射过滤每个传入请求,并将其传递给在 Spring 上下文中定义的安全过滤器。

问题是,servlet 过滤器由 servlet 容器管理,而不是由 spring 管理。您可能需要注入一些弹簧组件到您的过滤器。

所以,如果你需要这样的东西:

public class FooFilter {


@Inject
private FooService service;


public void doFilter(....) { .. }


}

然后需要委托过滤器代理。

什么是 Servlet 过滤器?

Servlet 过滤器 通常是一个 JavaWebApp 概念。您可以在任何 webapp 中使用 servlet 过滤器,无论您是否在应用程序中使用 Spring 框架。

这些过滤器可以在请求到达目标 servlet 之前拦截它们。您可以在 servlet 过滤器中实现通用功能,比如授权。一旦实现,您可以将 web.xml 中的过滤器配置为应用于特定的 servlet、特定的请求 url 模式或所有 url 模式。

在哪里使用 servlet 过滤器?

现代网络应用程序可以有几十个这样的过滤器。授权、缓存、 ORM 会话管理和依赖注入通常是借助 servlet 过滤器实现的。所有这些过滤器都需要在 web.xml中注册。

Instantiating Servlet Filters - without Spring Framework

Servlet 容器创建在 web.xml中声明的 Filter 的实例,并在适当的时候调用它们(例如,在处理 servlet 请求时)。现在,如果你像大多数依赖注入(DI)爱好者一样,你可能会说创建实例是我的 DI 框架(Spring)做得更好的地方。我不能用 Spring 创建 servlet 过滤器,这样它们就可以适应所有的 DI 优点了吗?

DelegatingFilterProxy,以便 Spring 创建筛选器实例

这就是 DelegatingFilterProxy介入的地方。DelegatingFilterProxy是 SpringFramework 提供的 javax.servlet.Filter接口的实现。一旦在 web.xml 中配置了 DelegatingFilterProxy,就可以在 Spring 配置中声明执行过滤的实际 豆子。通过这种方式,Spring 创建执行实际过滤的 bean 的实例,并且您可以使用 DI 来配置这些 bean。

注意,在 web.xml中只需要一个 DelegatingFilterProxy声明,但是可以在应用程序上下文中将多个过滤 bean链接在一起。

这里有某种魔力,但到最后,一切都是一个确定的程序。

如上所述,代理过滤器是一个 Filter,其目标是“ 授权给实现 Filter 接口 的 Spring 管理 bean”,也就是说,它在 Spring 应用程序上下文中找到一个 bean (“目标 bean”或“委托”)并调用它。这怎么可能?因为这个 bean 实现了 javax.servlet。Filter,其 doFilter 方法被调用。

哪种豆子叫什么?“支持“ targetBeanName”[ ... ] ,在 Spring 应用程序上下文中指定目标 bean 的名称。”

正如您在 web.xml 中看到的,Bean 的名称是“ < em > springSecurityFilterChain ”

So, in the context of a web application, a Filter instantiates a bean called "springSecurityFilterChain" in your application context and then delegate to it via the doFilter() method.

请记住,您的应用程序上下文是用所有的始终应用程序的 CONTEXT (XML)文件定义的,例如: applicationContext.XML 和 applicationContext-security.XML。

因此,尝试 找到一个叫做“ springSecurityFilterChain”的 bean在后者..。

... 和 也许你做不到(例如,如果您遵循教程或者如果您使用 Roo 配置安全性)

这就是神奇之处: 有一个配置安全性的新元素,大概是

<http auto-config="true" use-expressions="true">

因为它是由 http://www.springframework.org/schema/security/spring-security-3.0.xsd允许的,将做到这一点。

当 Spring 使用 XML 文件加载应用程序上下文时,如果它找到一个元素,它将尝试设置 HTTP 安全性,即过滤器堆栈和受保护的 URL,并注册名为“ springSecurityFilterChain”的 FilterChainProxy。

或者,您可以用传统的方式定义 bean,即:

<beans:bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">

但是不太推荐这样做,因为您需要进行大量的配置(所有要使用的过滤器)。他们有十几个人)

I have been perplexed by "springSecurityFilterChain" in web.xml and found this answer in springframework security document:

The <http> element encapsulates the security configuration for the web layer of your application. >It creates a FilterChainProxy bean named "springSecurityFilterChain" which maintains the stack of >security filters which make up the web security configuration [19]. Some core filters are always >created and others will be added to the stack depending on the attributes child elements which are >present. The positions of the standard filters are fixed (see the filter order table in the >namespace introduction), removing a common source of errors with previous versions of the framework >when users had to configure the filter chain explicitly in theFilterChainProxy bean. You can, of >course, still do this if you need full control of the configuration.

Here is the link http://docs.spring.io/spring-security/site/docs/3.0.x/reference/appendix-namespace.html

这是一个很长的时间,但我有同样的问题,我发现了这一点: https://www.javacodegeeks.com/2013/11/spring-security-behind-the-scenes.html

我试图通过删除有问题的过滤器和添加过滤器来运行我的 Spring 安全项目。我发现,如果我们添加过滤器,只有在那时调用才会重定向到 Spring-security 配置中定义的必需登录页面。

因此,我同意@Ryan 的回答。