我有一个基于Spring的Web应用程序,有两个servlet - 一个用于MVC,另一个用于spring-ws。应用程序中使用了几个bean,它们使用注释进行自动装配。每次应用程序启动时,它都会创建每个bean类型的3个实例 - 即使它们是单例范围的。 @PostConstruct方法也为每个方法调用三次。
据我所知,有3个应用程序上下文= 1个常用+ 2个servlet,但每个bean,控制器,端点等都创建了三次。至少在父应用程序上下文中加载的公共bean应该只实例一次。
组件扫描的base-package属性指向不相交的包。
我使用了一个类来转储上下文信息(https://gist.github.com/1347171),看起来有三个不同的上下文具有相同的结构(相同的bean)。他们的id是“/ project /”,“/ project / rest”,“/ project / soap”。
我尝试注释掉ContextLoaderListener,删除soap servlet及其相关的XML文件(applicationContext& soap-servlet),并将常用内容移动到其余的servlet中(这样只有一个配置xml,只有一个组件 - 扫描),我仍然得到每个bean的3个实例。在这种情况下,应用程序上下文ID是“/ Project /”(确切的大小写),“/ project /”和“/ project /”。
的web.xml
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<servlet>
<servlet-name>rest</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>rest</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>soap</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
<init-param>
<param-name>transformWsdlLocations</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>soap</servlet-name>
<url-pattern>/soap/*</url-pattern>
</servlet-mapping>
的applicationContext.xml
<context:annotation-config/>
<context:component-scan base-package="test.common"/>
<task:annotation-driven/>
rest-servlet.xml
<mvc:annotation-driven/>
<context:component-scan base-package="test.rest"/>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<util:list id="beanList">
<ref bean="formHttpMessageConverter"/>
</util:list>
</property>
</bean>
<bean id="formHttpMessageConverter"
class="org.springframework.http.converter.FormHttpMessageConverter"/>
<mvc:interceptors>
<bean class="test.rest.Interceptor"/>
</mvc:interceptors>
皂servlet.xml中
<sws:annotation-driven/>
<context:component-scan base-package="test.soap"/>
<sws:dynamic-wsdl
id="service"
portTypeName="service"
locationUri="/soap/service"
targetNamespace="http://server/soap">
<sws:xsd location="/WEB-INF/SoapService.xsd"/>
</sws:dynamic-wsdl>
<sws:interceptors>
<bean id="validatingInterceptor"
class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
<property name="schema" value="/WEB-INF/SoapService.xsd"/>
<property name="validateRequest" value="true"/>
<property name="validateResponse" value="true"/>
</bean>
</sws:interceptors>
答案 0 :(得分:0)
在bean上使用javax.ejb.Singleton注释。
答案 1 :(得分:0)
原因是Spring mvc上下文初始化和这些神奇的注释默认值有点令人困惑的文档:(。
由于以下原因,您可能有三份副本:
事实上,<mvc:annotation-driven>
拥有自定义适配器的所有标签,请检查您想要的架构。然而,另一种解决这个问题的方法是在跟踪模式下进行痛苦的调试,并查看哪个bean实际上正在创建适配器。在您的适配器构造函数中放置一个断点,然后在DispatcherServlet-&gt; mapperHandler-&gt;拦截器 - &gt; mapping-&gt; context-&gt; configFileLocation中查看堆栈以查看正在创建此bean的文件
如果您确实想要自定义消息转换器,那么您应该这样做:
<mvc:annotation-driven
content-negotiation-manager="contentNegotiationManager">
<mvc:message-converters register-defaults="false">
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="afterBurnerObjectMapper"/>
</bean>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.FormHttpMessageConverter"/>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>