Spring MVC的DelegatingFilterProxy有什么意义?

时间:2011-07-17 16:34:21

标签: java spring spring-mvc spring-security

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

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

我正在试图找出它为什么存在以及它是否真的需要它。

我找到了this explanation in the Spring docs,但这对我没有意义:

似乎暗示该组件是web.xml中定义的servlet与Spring applicationContext.xml中定义的组件之间的“粘合剂”。

  

7.1 DelegatingFilterProxy

     

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

     

使用DelegatingFilterProxy时,您会在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能够受益于Spring Web应用程序上下文生命周期支持和配置灵活性。 bean必须实现javax.servlet.Filter,并且必须与filter-name元素中的名称相同。有关详细信息,请阅读Javadoc for DelegatingFilterProxy

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

7 个答案:

答案 0 :(得分:122)

这里有一些魔力,但最后,一切都是确定性的程序。

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

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

正如您在web.xml中看到的那样, bean的名称是“ springSecurityFilterChain

因此,在Web应用程序的上下文中,Filter在应用程序上下文中实例化一个名为“springSecurityFilterChain”的bean,然后通过doFilter()方法委托给它。

请记住,您的应用程序上下文是使用所有APPLICATION-CONTEXT(XML)文件定义的。例如:applicationContext.xml AND 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">

但它不太值得推荐,因为你需要进行大量的配置(你将要使用的所有过滤器。并且有超过十几个)

答案 1 :(得分:63)

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

输入DelegatingFilterProxy。编写一个Filter实现并使其成为一个Spring bean,但不是将自己的Filter类添加到web.xml,而是使用DelegatingFilterProxy,并在Spring上下文中为其指定过滤器的bean名称。 (如果没有显式提供名称,它使用“filter-name”。)然后在运行时,DelegatingFilterProxy处理查找真实实现的复杂性 - 您在Spring中编写和配置的实现 - 并将请求路由到它。所以在运行时,就好像你已经在web.xml中列出了你的过滤器,但是你可以像任何其他Spring bean一样连接它。

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

答案 2 :(得分:40)

什么是Servlet过滤器?

一般来说,

Servlet filters是一个Java WebApp概念。无论是否在应用程序中使用Spring框架,都可以在任何webapp中使用servlet过滤器。

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

使用servlet过滤器的地方?

现代网络应用可以拥有数十种此类过滤器。授权,缓存,ORM会话管理和依赖注入等操作通常借助servlet过滤器实现。所有这些过滤器都需要在web.xml中注册。

实例化Servlet过滤器 - 没有Spring Framework

您的servlet容器创建在web.xml中声明的Filters实例,并在适当的时候调用它们(即,在处理servlet请求时)。现在,如果你像大多数依赖注入(DI)粉丝一样,你可能会说我的DI框架(Spring)做得更好。我不能得到用Spring创建的servlet过滤器,所以它们适合所有DI的优点吗?

DelegatingFilterProxy,以便Spring创建过滤器实例

这是DelegatingFilterProxy步骤的地方。DelegatingFilterProxy是Spring Framework提供的javax.servlet.Filter接口的一个实现。在web.xml中配置DelegatingFilterProxy后,您可以声明在spring配置中执行过滤的实际 beans 。这样,Spring创建了进行实际过滤的bean实例,您可以使用DI来配置这些bean。

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

答案 3 :(得分:14)

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

所以,如果你需要类似的东西:

public class FooFilter {

    @Inject
    private FooService service;

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

}

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

答案 4 :(得分:1)

你说'粘'的东西是正确的。正如FilterChainProxy的JavaDocs中所写:

  

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

请参阅博客Behind the Spring Security Namespace的FIlterChainProxy部分,以获得出色的解释。

答案 5 :(得分:0)

我被#Spring; SpringSecurityFilterChain&#34;感到困惑。在web.xml中,在springframework安全文档中找到了这个答案:

  

<http>元素封装了应用程序的Web层的安全配置。 &gt;它创建一个名为&#34; springSecurityFilterChain&#34;的FilterChainProxy bean。它维护着构成Web安全配置的&gt;安全过滤器的堆栈[19]。一些核心过滤器总是被创建,并且其他核心过滤器将被添加到堆栈中,这取决于存在的属性子元素。标准过滤器的位置是固定的(请参阅&gt;名称空间简介中的过滤器顺序表),当用户必须在FileChainProxy bean中显式配置过滤器链时,使用以前版本的框架删除常见的错误源&gt;如果您需要完全控制配置,您当然可以执行此操作。

以下是链接http://docs.spring.io/spring-security/site/docs/3.0.x/reference/appendix-namespace.html

答案 6 :(得分:0)

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

我尝试通过删除有问题的过滤器并添加它来运行我的Spring安全项目。我发现如果我们添加过滤器,那么调用将重定向到spring-security配置中定义的所需登录页面。

因此,同意@Ryan的答案。