为DelegatingFilterProxy分离Spring上下文
我正在尝试使用DelegatingFilterProxy将筛选器安装到Spring Web应用程序中。 该应用程序对我来说是一个黑匣子。 我无法控制它,但我知道它使用Spring。 我只控制我的过滤器。
应用程序本身以通常的方式在web.xml(tomcat 7)中配置,使用通过<context-param>
指定的Spring配置文件<listener>...ContextLoaderListener...</listener>
<context-param>
。
我的第一个尝试是分享应用程序的上下文。 我将自己的spring配置XML添加到context-param。 我的过滤器加载得很好,但我打破了应用程序。 我不确定它是如何破坏的,但看起来它不能再建立数据库连接。 我检查了明显的事情。 没有bean名称冲突或属性名称冲突。
我真正想做的是有2个完全独立的上下文,因此,大概我的过滤器将无法影响黑匣子应用程序。 有没有一种方法可以配置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>
时间过去了:关于为什么在这种情况下共享上下文是一个坏主意,我有更多的信息。 事实证明,我有豆冲突。 特别是,我的过滤器和底层应用程序都使用了一个名为“dataSource”的bean(当然)。
一旦我重新命名了我的bean,我收到了Spring的一个非常明确的信息:
没有定义[javax.sql.DataSource]类型的合格bean:期望单个匹配的bean,但找到2:dataSource,deoDataSource
据推测,该应用程序使用按类型而不是名称连接,所以我有明显的冲突。
所以! 原始问题仍然存在:是否可以配置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
来做到这一点。