【问题标题】:What's the point of Spring MVC's DelegatingFilterProxy?Spring MVC 的 DelegatingFilterProxy 有什么意义?
【发布时间】:2011-10-07 04:51:41
【问题描述】:

我在 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 委托过滤器代理

使用 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 所做的是将过滤器的方法委托给从 Spring 应用程序上下文获取的 bean。这使 bean 能够从 Spring Web 应用程序上下文生命周期支持和配置灵活性中受益。该 bean 必须实现 javax.servlet.Filter 并且它必须与 filter-name 元素中的名称相同。阅读Javadoc for DelegatingFilterProxy了解更多信息

那么,如果我从web.xml 中删除它,会发生什么?我的 servlet 将无法与 Spring 容器通信?**

【问题讨论】:

    标签: java spring spring-mvc spring-security


    【解决方案1】:

    这里有某种魔法,但归根结底,一切都是确定性程序。

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

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

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

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

    请记住,您的应用程序上下文是使用所有应用程序上下文 (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">
    

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

    【讨论】:

    • "applicationContext-security.xml AND applicationContext-security.xml" 是相同的文件名两次。
    • 谢谢musiKk(我觉得你可以直接编辑帖子)
    • 这是我一直在寻找的解释并为我清理了一切。
    • @jbbarquero:你是对的,但我不确定正确的版本应该是什么。我倾向于把它留给原作者来修复,以免无意中改变意思。
    • 好的。无论如何,我非常感谢您为改进我的回复所提供的帮助。再次感谢,musiKk
    【解决方案2】:

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

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

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

    【讨论】:

    • 感谢您发表这篇富有启发性的评论。我现在正在学习 Spring Security,试图理解它来进行定制。我不知道什么是 servlet 过滤器或什么是 springs 过滤器。您对 AOP 的了解清楚地说明了为什么会有过滤器而不是仅使用 servlet........所以您不必在每个 servlet/资源中一遍又一遍地编写相同的前/后处理跨度>
    • 哇。这个解释正是我需要的。感谢您分享您的知识。
    • @Ryan Stewart 如果我有两个 bean 在 applicationContext 中实现 Filter 接口,并且我想按顺序执行,那我该怎么做呢?
    • @skaffman 如果我有两个bean在applicationContext中实现Filter接口,我想按顺序执行,那我该怎么做呢?
    【解决方案3】:

    什么是 Servlet 过滤器?

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

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

    servlet 过滤器在哪里使用?

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

    实例化 Servlet 过滤器 - 没有 Spring 框架

    您的 servlet 容器创建在 web.xml 中声明的过滤器实例,并在适当的时间(即,在为 servlet 请求提供服务时)调用它们。现在,如果您像大多数依赖注入 (DI) 粉丝一样,您可能会说创建实例是我的 DI 框架 (Spring) 做得更好的地方。我不能让我的 servlet 过滤器使用 Spring 创建,以便它们适合所有 DI 优点吗?

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

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

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

    【讨论】:

    • 解释得很好。
    【解决方案4】:

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

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

    public class FooFilter {
    
        @Inject
        private FooService service;
    
        public void doFilter(....) { .. }
    
    }
    

    那么您需要委托过滤器代理。

    【讨论】:

      【解决方案5】:

      关于“胶水”的东西,你是对的。正如FilterChainProxy的JavaDocs所写:

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

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

      【讨论】:

        【解决方案6】:

        一直被web.xml中的“springSecurityFilterChain”迷惑,在springframework安全文档中找到了这个答案:

        &lt;http&gt; 元素封装了应用程序 Web 层的安全配置。 >它创建一个名为“springSecurityFilterChain”的FilterChainProxy bean,它维护组成Web安全配置[19]的>安全过滤器堆栈。一些核心过滤器总是 >created 并且其他的将被添加到堆栈中,具体取决于 >present 的属性子元素。标准过滤器的位置是固定的(请参阅>命名空间介绍中的过滤器顺序表),消除了以前版本框架的常见错误源>当用户必须在FilterChainProxy bean中显式配置过滤器链时。当然,如果您需要完全控制配置,您仍然可以这样做。

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

        【讨论】:

          【解决方案7】:

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

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

          因此,同意@Ryan 的回答。

          【讨论】:

            猜你喜欢
            • 2012-06-23
            • 2011-03-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-06-15
            • 2012-03-30
            • 2011-10-11
            • 2013-10-22
            相关资源
            最近更新 更多