Java 如何防止多个bean实例?

Java 如何防止多个bean实例?,java,spring,glassfish,Java,Spring,Glassfish,我有一个基于Spring的web应用程序,有两个servlet——一个用于MVC,一个用于SpringWS。应用程序中使用了几个bean,它们是使用注释自动连接的。每次应用程序启动时,它都会为每种bean类型创建3个实例,即使它们是单例范围的。@PostConstruct方法也会为每个方法调用三次 我知道有3个应用程序上下文=1个公共+2个servlet,但每个bean、控制器、端点等都创建了三次。至少在父应用程序上下文中加载的公共bean应该只实例化一次 组件扫描的基本包属性指向不相交的包 我

我有一个基于Spring的web应用程序,有两个servlet——一个用于MVC,一个用于SpringWS。应用程序中使用了几个bean,它们是使用注释自动连接的。每次应用程序启动时,它都会为每种bean类型创建3个实例,即使它们是单例范围的。@PostConstruct方法也会为每个方法调用三次

我知道有3个应用程序上下文=1个公共+2个servlet,但每个bean、控制器、端点等都创建了三次。至少在父应用程序上下文中加载的公共bean应该只实例化一次

组件扫描的基本包属性指向不相交的包

我使用了一个类来转储上下文信息https://gist.github.com/1347171 似乎有三种不同的上下文具有相同的结构和相同的bean。它们的id是/project/、/project/rest、/project/soap

我尝试注释ContextLoaderListener,删除soap servlet及其关联的XML文件applicationContext&soap servlet,并将常见内容移动到rest servlet中,这样就只有一个配置XML和一个组件扫描,每个bean仍然有3个实例。在这种情况下,应用程序上下文id是/Project/exact-casing、/Project/和/Project/

web.xml

applicationContext.xml

soap-servlet.xml


在您的bean上使用javax.ejb.Singleton注释。

在您的bean上使用javax.ejb.Singleton注释。

原因是关于spring mvc上下文初始化的文档有点混乱,这些神奇的注释默认值:

由于以下原因,您可能有三份副本:

contextConfigLocation定义创建一个根webapp上下文,每个应用程序只加载一个该上下文,并在所有servlet中共享。每个-servlet-config.xml文件都可以访问这些bean,但反之亦然。 因此,第二个实例来自您的-servlet应用程序上下文,因为您再次明确定义了注释驱动。 不确定您使用的是哪个spring框架版本,但通过定义注释驱动和自定义请求映射适配器,您几乎创建了两个。 事实上,如果你有所有的标签来定制你的适配器,检查你想要的模式。然而,另一种解决方法是在跟踪模式下进行痛苦的调试,并查看到底是哪个bean在创建适配器。在适配器构造函数中放置一个断点,然后查看DispatcherServlet->mapperHandler->interceptor->mapping->context->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>  

原因是关于SpringMVC上下文初始化的文档有点混乱,还有这些神奇的注释默认值:

由于以下原因,您可能有三份副本:

contextConfigLocation定义创建一个根webapp上下文,每个应用程序只加载一个该上下文,并在所有servlet中共享。每个-servlet-config.xml文件都可以访问这些bean,但反之亦然。 因此,第二个实例来自您的-servlet应用程序上下文,因为您再次明确定义了注释驱动。 不确定您使用的是哪个spring框架版本,但通过定义注释驱动和自定义请求映射适配器,您几乎创建了两个。 事实上,如果你有所有的标签来定制你的适配器,检查你想要的模式。然而,另一种解决方法是在跟踪模式下进行痛苦的调试,并查看到底是哪个bean在创建适配器。在适配器构造函数中放置一个断点,然后查看DispatcherServlet->mapperHandler->interceptor->mapping->context->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>  

你说它们被创造了三次是什么意思?实例化三次?有三个参考资料吗?我在这里使用与您几乎相同的设置,从未注意到任何不规则的活动。你能给我们看一下导致你得出这些结论的任何证据吗?它们被实例化了三次——这可以通过在构造函数中设置断点/跟踪来发现。每个bean的@PostConstruct注释方法也被调用了三次,这意味着实例是“真实的”,而不仅仅是本文所说的一些代理:它们被创建了三次是什么意思?实例化三次?有三个参考资料吗?我在这里使用与您几乎相同的设置,从未注意到任何不规则的活动。你能给我们看一下导致你得出这些结论的任何证据吗?它们被实例化了三次——这可以通过在构造函数中设置断点/跟踪来发现。@PostConstruct anno 每个bean的方法也被调用三次,这意味着实例是“真实的”,而不仅仅是本文所说的一些代理:
<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>
<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>