围绕 Spring 集成和原型范围的谜团 [英] Mystery around Spring Integration and prototype scope

查看:44
本文介绍了围绕 Spring 集成和原型范围的谜团的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

嗯,很可能没有任何神秘之处,但我只是不够聪明,无法弄清楚我的问题是什么.然而通常它毕竟是个谜!

Well, very likely there isn't any mystery but I am just not smart enough to figure out what my problem is. However usually it is the mystery after all!

抱歉介绍,我的问题是原型范围似乎对我不起作用.我创建了一个带有 Spring Integration 流的 REST 服务(流的前面有一个 http 入站网关).大多数 bean 的作用域是原型.我通过用线程调用它十次来测试流程.我还记录了 bean 引用(只需在被调用的对象中打印this")并且我看到了十次相同的引用!

Sorry for the introduction, my problem is that the prototype scope doesn't seem to work for me. I have created a REST service with a Spring Integration flow (there is a http inbound gateway in the front of the flow). The scopes of most of the beans are prototype. I tested the flow by calling it ten times with threads. Also I logged the bean references (just print the 'this' in the object being called) and I saw the same reference ten times!

 e.g. org.protneut.server.common.utils.XmlToMapConverter@755d7bc2  

据我所知,这意味着没有为 XmlToMapConverter 创建新实例,而是使用了十次相同的实例.我说得对吗?
很可能我错误地配置了 Spring,但我就是找不到我错过了什么.

To my knowledge it means that no new instance is being created for the XmlToMapConverter but using the same instance ten times. Am I right?
Very likely I configured the Spring incorrectly but I just cannot find out what I missed.

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4" 
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/SpringIntegration-servlet.xml</param-value>
    </context-param>
    <servlet>
        <servlet-name>SpringIntegration</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value></param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>SpringIntegration</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

SpringIntegration-servlet.xml

SpringIntegration-servlet.xml

<beans ...>
    <mvc:annotation-driven/>
    <context:component-scan base-package="org.protneut.server.controller, org.protneut.server.common.persistence.service" />
    <jpa:repositories base-package="org.protneut.server.common.persistence.repository"/>
    <!-- ********************* importing the mysql config ********************* -->
    <import resource="/mysql-config-context.xml"/>
    <!-- ********************* importing the message flow ********************* -->
    <import resource="classpath:META-INF/spring/integration/processing_req_wokflow.xml"/>
    <tx:annotation-driven />
    <!-- ************************************************************************* -->
    <!-- ******************************** for JPA ******************************** -->
    <!-- ************************************************************************* -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="packagesToScan" value="org.protneut.server.common.persistence.model" />
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect"/>
            </bean>
        </property>
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.show_sql">false</prop>
                <prop key="hibernate.format_sql">true</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
            </props>
        </property>
    </bean>
    <!-- ********************* the used property files ********************* -->
    <context:property-placeholder location="classpath:protneut-server-config.properties"/>
    <!-- 
    ****************************************************************************************
    **********************  Beans used in the Spring Integration flow ********************** 
    ****************************************************************************************
    -->
    <!-- it has to be prototype, it cannot be request as it is in an async call so it is not in the request! -->
    <bean id="logManager" class="org.protneut.server.log.LogManager" scope="prototype"></bean>
    <bean id="convertRestToWorkflowBean" class="org.protneut.server.rest.ConvertRestMessageToWorkflowBean" scope="prototype"/>
    <bean id="xmlToMapConverter" class="org.protneut.server.common.utils.XmlToMapConverter" scope="prototype"/>
    <bean id="serviceStorageManager" class="org.protneut.server.cache.ServiceStorageManager" scope="singleton">
        <property name="cacheBeanDAO" ref="cacheBeanDAO"/>
    </bean>
    <bean id="serviceCall" class="org.protneut.server.call.ServiceCall" scope="prototype">
        <property name="httpClient" ref="httpClient"/>
    </bean>
    <bean id="xmlResponseExtractor" class="org.protneut.server.extract.XmlResponseExtractor" scope="prototype">
        <property name="xmlToMapConverter" ref="xmlToMapConverter"/>
    </bean>
    ...
</beans>

流量配置

<?xml version="1.0" encoding="UTF-8"?>
<beans ..>
    <task:executor id="async_executor" pool-size="50"  />
    <!-- ***************************************************************************************************** -->
    <!-- ************************************* WORKFLOW STARTING ********************************************* -->
    <!-- ***************************************************************************************************** -->
    <int-http:inbound-gateway id="receivingRest-inboundGateway"
        supported-methods="POST" path="/service/get"
        request-payload-type="java.lang.String" reply-timeout="10000"
        request-channel="arrivedRestReq_channel" auto-startup="true"
        error-channel="error_channel" reply-channel="restResponse-channel" >
    </int-http:inbound-gateway>
    <int:channel id="arrivedRestReq_channel" scope="prototype"></int:channel>
    <int:json-to-object-transformer type="java.util.Map"
        input-channel="arrivedRestReq_channel"
        output-channel="fromConvertToActivator-channel"
        id="convertJsonToMap_">
    </int:json-to-object-transformer>
    <int:channel id="fromConvertToActivator-channel"></int:channel>
    <int:service-activator
        input-channel="fromConvertToActivator-channel"
        output-channel="toCallChain-channel"
        id="convertRestToWorkflowBean-serviceActivator"
        ref="convertRestToWorkflowBean" method="convert">
    </int:service-activator>
    <int:channel id="toCallChain-channel"></int:channel>
    <int:chain input-channel="toCallChain-channel" id="call_chain">
        <int:service-activator
            id="serviceStorageManager-serviceActivator"
            ref="serviceStorageManager" method="getServiceInfo">
        </int:service-activator>
        <int:service-activator id="serviceRequestCreator-serviceActivator" ref="serviceRequestCreator" method="create"/>
        <int:service-activator id="call-serviceActivator"
            ref="serviceCall" method="call">
        </int:service-activator>
        <int:router expression="payload.extractType.name()"
            id="responseExtractor-router">
            <int:mapping value="XPATH" channel="xmlResponse-channel"/>
            <int:mapping value="JSONPATH" channel="jsonResponse-channel"/>
        </int:router>
    </int:chain>
    ...
    <int:service-activator id="xmlResponseExtractor-serviceActivator"
    ref="xmlResponseExtractor" method="extract" input-channel="xmlResponse-channel" output-channel="toRestResponseCreator_chain"></int:service-activator>
</beans>

所以我将 XmlToMapConverter 的范围定义为原型,但我仍然无法在新请求下创建新对象.情况与 convertRestToWorkflowBean 相同,它是流程中的第一个服务调用(服务激活器).你能向我解释一下问题出在哪里吗?
谢谢,V.

So I defined the scope of XmlToMapConverter is prototype but still I can't have new object at a new request. The situation is the same for convertRestToWorkflowBean which is the first service call in the flow (service-activator). Could you please explain to me where the problem is?
Thanks, V.

推荐答案

我没有看到 xmlToMapConverter 的用法,但我看到了这个:

I don't see xmlToMapConverter usage, but I see this:

<int:service-activator
    input-channel="fromConvertToActivator-channel"
    output-channel="toCallChain-channel"
    id="convertRestToWorkflowBean-serviceActivator"
    ref="convertRestToWorkflowBean" method="convert">

你在哪里使用它:

<bean id="convertRestToWorkflowBean" class="org.protneut.server.rest.ConvertRestMessageToWorkflowBean" scope="prototype"/>

您面临的问题称为范围阻抗.那是因为 填充了几个 singleton bean,因此对 prototype 的引用变成了 singleton,也是.

The issue you are facing is called scope impendance. That's because <int:service-activator> populates several singleton beans, hence the reference to your prototype becomes as singleton, too.

克服这个问题的一种方法是从那里使用 SpEL:

One way to overcome that to use SpEL from there:

<int:service-activator
    input-channel="fromConvertToActivator-channel"
    output-channel="toCallChain-channel"
    id="convertRestToWorkflowBean-serviceActivator"
    expression="@convertRestToWorkflowBean.convert(payload)"/>

在这种情况下,您的 convertRestToWorkflowBean 在每次调用时从 BeanFactory 中检索.

In this case your convertRestToWorkflowBean is retrieved from the BeanFactory on each call.

另一个技巧如下:

<bean id="convertRestToWorkflowBean" class="org.protneut.server.rest.ConvertRestMessageToWorkflowBean" scope="prototype">
    <aop:scoped-proxy/>
</bean>

在这种情况下,您的 bean 将被包装到 ScopedProxyFactoryBean,并且所有调用都将根据需要委托给您的 prototype.

In this case your bean will be wrapped to the ScopedProxyFactoryBean and all invocation will be delegated to your prototype on demand.

这篇关于围绕 Spring 集成和原型范围的谜团的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆