Spring单例被调用两次

10

我的Spring应用程序遇到了一些问题。

我有非常简单的Spring Bean,它们被注入到其他各种Spring Bean中。在调试过程中,我发现它们被调用了两次,构造函数和@PostConstruct都被调用了两次。

我的应用程序没有前端技术。它只是用于后端任务相关的。

Spring配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:lang="http://www.springframework.org/schema/lang" xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd">


    <context:component-scan base-package="com.green.integration" />

    <!-- ######################################################## -->
    <!-- EXPOSING SPRING BEAN VIA HTTPINVOKER SPRING REMOTING -->
    <!-- ######################################################## -->

    <bean name="/switch"
        class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
        <property name="service" ref="SwitchController" />
        <property name="serviceInterface"
            value="com.green.ISwitchController" />
    </bean>

    <!-- Load in application properties reference -->
    <bean id="applicationProperties"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:application.properties" />
    </bean>


    <bean id="mongo" class="com.mongodb.Mongo">
        <constructor-arg value="${mongo.server}" />
        <constructor-arg value="${mongo.port}" />
    </bean>

    <bean id="morphia" class="com.google.code.morphia.Morphia">
    </bean>


</beans>

Spring Bean类

@Repository
public class TransactionDAO extends BasicDAO<Transaction, ObjectId>  {
    private Datastore datastore;

    @Autowired
    public TransactionDAO(Mongo mongo, Morphia morphia) {
        super(mongo, morphia, "itransact");
        morphia.map(Transaction.class);
        // TO USE MONGO WITHOUT SECURITY
        this.datastore = morphia.createDatastore(mongo, "itransact");
        logger.debug("***** CONNECTED TO MONGODB SUCCESSFULLY *****");
        this.datastore.ensureIndexes();
        // this.datastore.ensureCaps();
    }
}

构造函数“TransactionDAO”被调用了两次。

我尝试通过

Throwable t = new Throwable();
System.out.println(t.getStackTrace()[1].toString());

每次它都显示以下内容。
sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

1
你确定 @PostConstruct 也被调用了两次吗?构造函数被调用两次可以很容易解释,但是 @PostConstruct 不行。 - Tomasz Nurkiewicz
1
你有调度器Servlet的配置吗? - Juan Alberto López Cavallotti
1
您的Spring配置中未包含您列出的DAO类。这里缺少信息。 - stevedbrown
1
@JuanAlbertoLópezCavallotti Juan,我通过删除分发器servlet并且bean只初始化一次进行了验证。是分发器导致了两次初始化。那么请问应该如何修复? - Faisal Basra
@TomaszNurkiewicz 构造函数被调用两次的原因很容易解释,但是 @PostConstruct 不行......如果在同一个 JVM 中从不同的上下文中调用它,则每次在构造函数之后都会调用 PostConstruct。您评论背后的理由是什么? - raffian
显示剩余7条评论
2个回答

17

我刚刚弄清楚了问题,并特别感谢@Juan Alberto给了我提示。

问题描述:实际上,我为contextListner和dispatcher servlet都提供了一个applicationContext.xml文件。所以第一次bean初始化为Spring核心,第二次为Spring Dispatcher。

我现在将配置拆分为applicationContext.xml和applicationContext-dispatcher.xml,它们仅具有相关的配置,我的bean只会正确地初始化一次。

有问题的配置

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>


<servlet>
    <servlet-name>remoting</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
    </init-param>
    <load-on-startup>0</load-on-startup>
</servlet>

已解决的配置

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>


<servlet>
    <servlet-name>remoting</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext-dispatcher.xml</param-value>
    </init-param>
    <load-on-startup>0</load-on-startup>
</servlet>

4
我不理解应该把什么内容放在 applicationContext-dispatcher.xml 中,以及应该把什么内容放在 applicationContext.xml 中。 - Allan Ruin

5
实际上,你的问题可能是你在dispatcher servlet和你的spring context中定义了bean。dispatcher提供了一个不同的上下文,但它是主上下文的一个子上下文,因此正确的做法是让你的主上下文扫描你的“model classes”,而dispatcher只扫描控制器。

我希望这可以帮助你。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接