所有的Spring Framework bean都被复制,以上下文加倍的形式(servlet + ContextLoaderListener)
问题内容:
-
如果我 通过调度程序servlet 创建spring上下文,则会在
DelegatingFilterProxy
filter中遇到错误:java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:251)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.apache.logging.log4j.core.web.Log4jServletFilter.doFilter(Log4jServletFilter.java:66) -
如果我 通过
ContextLoaderListener
* 没有servlet来 创建spring上下文 ,404
则会出现错误 * -
如果我 同时通过servlet和侦听器 创建spring上下文 ,则 我具有重复的上下文,因此所有Bean都是重复的,包括具有请求映射的控制器,双执行
@Scheduled
方法等。
如何在不复制上下文的情况下创建高级spring应用程序(包括大量过滤器等)?
我的web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>MyWebApplication</display-name>
<servlet>
<servlet-name>springDispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring.xml
</param-value>
</context-param>
<!-- UTF-8 -->
<filter>
<filter-name>encoding-filter</filter-name>
<filter-class>
org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding-filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Spring Security -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
问题答案:
如果您使用与Spring相关的servlet过滤器,并且还使用mvc控制器,那么您将同时需要:
- ContextLoaderListener与
- DispatcherServlet-spring-configuration
两者都创建自己的servlet上下文。ContextLoaderListener创建 父上下文
(有时称为内部上下文)。而DispatcherServlet的创建 子上下文
(父上下文)(有时也称为外上下文)。子上下文的Bean可以访问父上下文的Bean,但反之则不能。
在不太简单的Web应用程序中,您需要两个上下文,因为有许多servlet过滤器需要一个已经创建的spring上下文。另一方面,所有控制器内容都需要ServletContext,而这仅是由Dispatcher
Servlet创建的。
另一点是,您不应该将每个bean都创建两次(有时这没问题,而有时则是)。因此,您需要具有两种弹簧配置,一种用于内部环境,一种用于其他环境。而且,您需要为每个bean决定它是属于内部上下文还是属于外部上下文。
经验法则是:将所有内容放入内部上下文中,除非需要Servlet上下文或与Web前端紧密相关的内容,例如MVC-Controllers,Tiles配置等。