首页 文章

DelegatingFilterProxy的单独Spring上下文

提问于
浏览
2

我正在尝试使用DelegatingFilterProxy将过滤器安装到Spring Web应用程序中 . 该应用程序对我来说是一个黑盒子 . 我无法控制它,但我知道它使用Spring . 我只控制我的过滤器 .

应用程序本身以通常的方式在web.xml(tomcat 7)中配置, <listener>...ContextLoaderListener...</listener> ,通过 <context-param> 指定Spring配置 .

我的第一次尝试是分享应用程序的上下文 . 我将自己的spring config XML添加到context-param中 . 我的过滤器加载得很好,但我打破了应用程序 . 我不确定它是如何被破坏的,但看起来它不再能够 Build 数据库连接 . 我检查了明显的事情 . 没有bean名称冲突或属性名称冲突 .

我真正想做的是有两个完全独立的上下文,因此,据推测,我的过滤器无法影响黑盒应用程序 . 有没有办法我可以配置web.xml以使Spring为我的过滤器创建一个新的上下文?

stackoverflow上有几个类似的问题,但细节差别很大 .

我按照要求发布了我的web.xml,但请记住,这不是我想要做的 . 你在这里看到的是我的过滤器和共享相同上下文的web应用程序,这不是我想要的 . 我问是否有可能有两个完全独立的上下文,以便过滤器和Web应用程序完全相互隔离(至少在Spring级别) .

我的部分是过滤器声明和过滤器映射以及spring xml上下文配置的第二行(classpath:...)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>

    <display-name>xxx</display-name>
    <description>xxx</description>

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

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

    <context-param>
        <param-name>log4jConfigLocation</param-name>
        <param-value>/WEB-INF/log4j.properties</param-value>
    </context-param>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/spring/applicationContext.xml
            classpath:my-access-spring.xml
        </param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
    </listener>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <listener>
        <listener-class>flex.messaging.HttpFlexSession</listener-class>
    </listener>

    <servlet>
        <servlet-name>spring-flex</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value></param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet>
        <servlet-name>xxx-rest</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!-- Map all /messagbroker requests to the DispatcherServlet for handling -->
    <servlet-mapping>
        <servlet-name>spring-flex</servlet-name>
        <url-pattern>/messagebroker/*</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>xxx-rest</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>

    <error-page>
        <error-code>401</error-code>
        <location>/error-401.html</location>
    </error-page>

    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

</web-app>

时间流逝:我有更多的信息说明为什么在这种情况下共享上下文是个坏主意 . 事实证明,我DID有 beans 冲突 . 特别是,我的过滤器和底层应用程序都使用名为“dataSource”的bean(当然) .

一旦我重命名我的bean,我从Spring得到了一个非常明确的信息:

没有定义[javax.sql.DataSource]类型的限定bean:期望的单个匹配bean但找到2:dataSource,deoDataSource

据推测,应用程序按类型使用布线,而不是名称,因此我有明显的冲突 .

所以!最初的问题仍然存在:是否可以将Spring配置为仅针对我的过滤器创建单独的上下文?

谢谢,弗雷德

1 回答

  • 2

    您可以通过两种方式解决问题:

    • make Spring不使用你的bean进行自动装配

    • 为过滤器代理指定不同的spring上下文

    禁用自动装配

    可以通过XML配置将特定bean排除为自动装配候选者:

    <bean class="foo.bar.Baz" autowire-candidate="false" />
    

    定义第二个应用程序上下文

    我对你的问题的评论不正确 - 你不能让 ContextLoaderListener 加载两个单独的上下文 . 但是你可以通过使用 DispatcherServlet 为你加载第二个上下文来解决这个问题:

    <!-- Use this just to load second application context -->
    <servlet>
        <servlet-name>filterContextLoader</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:filter-context.xml</param-value>
        </init-param>
        <init-param>
            <param-name>contextAttribute</param-name>
            <param-value>filterContext</param-value>
        </init-param>
    </servlet>
    
    <filter>
        <filter-name>customFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <param-name>contextAttribute</param-name>
            <param-value>filterContext</param-value>
        </init-param>
    </filter>
    

    当然有一个缺点是 DispatcherServlet 将使用所谓的默认策略并自动注册各种不必要的bean(默认处理程序映射,处理程序适配器......) . 但这应该是无害的 . 如果你想在没有不必要的bean的情况下注册干净的上下文,你需要实现自己的 ServletContextListener 来做到这一点 .

相关问题