所有Spring框架的bean都会被复制,因为有双重的上下文(servlet+ContextLoaderListener)。

10 浏览
0 Comments

所有Spring框架的bean都会被复制,因为有双重的上下文(servlet+ContextLoaderListener)。

如果我通过dispatcher servlet创建spring上下文,我会在DelegatingFilterProxy过滤器中遇到错误:

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创建spring上下文,由于没有servlet,我只会遇到404错误。

如果我同时通过servlet和listener创建spring上下文,我会有重复的上下文,所有的bean都会重复,包括具有请求映射的控制器,双重执行@Scheduled方法等。

如何创建高级的spring应用程序(包括许多过滤器等),而不重复上下文?

我的web.xml文件:

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">

MyWebApplication

springDispatcher

org.springframework.web.servlet.DispatcherServlet

contextConfigLocation

/WEB-INF/spring.xml

1

springDispatcher

/

org.springframework.web.context.ContextLoaderListener

contextConfigLocation

/WEB-INF/spring.xml

encoding-filter

org.springframework.web.filter.CharacterEncodingFilter

encoding

UTF-8

forceEncoding

true

encoding-filter

/*

springSecurityFilterChain

org.springframework.web.filter.DelegatingFilterProxy

springSecurityFilterChain

/*

0
0 Comments

问题出现的原因是因为使用了与Spring相关的servlet过滤器,并且还使用了MVC控制器。在这种情况下,需要同时使用ContextLoaderListener和DispatcherServlet-spring-configuration。这两者都会创建自己的servlet上下文。ContextLoaderListener创建了父上下文(有时也称为内部上下文),而DispatcherServlet创建了父上下文的子上下文(有时也称为外部上下文)。子上下文的bean可以访问父上下文的bean,但反之则不行。

在一个不太简单的Web应用程序中,需要同时使用两个上下文,因为有许多servlet过滤器需要一个已创建的Spring上下文。另一方面,所有的控制器都需要一个ServletContext,而这个ServletContext只能由DispatcherServlet创建。

另一个问题是,不应该让每个bean都创建两次(有时候这没有问题,但有时候就有问题了)。因此,需要有两个Spring配置文件,一个用于内部上下文,一个用于外部上下文。并且,需要为每个bean决定它是属于内部上下文还是外部上下文。

经验法则是:将所有的东西都放在内部上下文中,除了那些需要ServletContext或与Web前端紧密相关的东西,例如MVC控制器、Tiles配置等。

解决方法是将所有的bean都放在applicationContext.xml中,这样可以解决问题,现在可以将一些bean移到web上下文中进行清理。需要注意的是,如果仍然将所有的bean放在webspring上下文中,仅仅分离XML文件是不会有帮助的。

另外需要注意的是,将业务层放在父上下文中,将Web前端委托给外部上下文(DispatcherServlet上下文)。

总结起来,问题的原因是因为使用了ContextLoaderListener和DispatcherServlet,并且需要同时使用两个上下文来解决不同的需求。解决方法是将bean分配到不同的上下文中,同时将业务层放在父上下文中,将Web前端委托给外部上下文。

0