当前位置: 首页 > 知识库问答 >
问题:

Spring集成和原型范围的奥秘

缪成天
2023-03-14

嗯,很可能没有任何谜团,但我只是不够聪明,不知道我的问题是什么。然而,通常它毕竟是谜团!

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

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

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

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

<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的范围是prototype,但我仍然不能在新请求下拥有新对象。convertRestToWorkflowBean的情况也一样,它是流(服务激活器)中的第一个服务调用。你能解释一下问题出在哪里吗<谢谢,V。

共有2个答案

孔波
2023-03-14

原型作用域bean将在每次调用Application ationContext.getBean(...)

您已经包含了bean定义,但没有展示其他服务如何引用它。我的猜测是,它在初始化期间被注入单例服务一次,因此只有一个。也许您需要调用ApplicationContext。每次获取一个新实例。

还有其他涉及最终调用getBean()的动态代理的解决方案,我现在在手机上,很难为您找到链接。

翟迪
2023-03-14

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

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

您面临的问题称为范围阻抗。那是因为<代码>

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

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

在这种情况下,每次调用时都会从BeanFactory检索您的convertRestToWorkflowBean。

另一个继续的技巧如下:

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

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

 类似资料:
  • 问题内容: 我有一个名为Bar的类,带有以下注释: 在私人成员上,我具有以下注释: 在春季配置中,我有一个Foo类的bean。如果用它定义的bean 不起作用,则出现以下异常: NoSuchBeanDefinitionException:找不到依赖项为Foo的匹配bean:期望至少有1个有资格作为此依赖项的自动装配候选的bean 一旦我将注入的bean作用域更改为正常工作。 是否自动布线原型作用域

  • 我想问一个关于JAXB将如何维护与生成的类相关联的值的一般性问题。我可以生成这个类,只要它在有效负载中就可以使用它,但是当我转到另一个spring集成过程时,对象似乎不会保留这些值。我知道必须有一种简单的方法来确保生成的对象保留其填充的内容。我可以重新实例化这个类,但这只是一个新的空类。 这是我想完成的事情 要生成的基本XML文档 这将产生 不过我选择得到这个xml可以使用然后我散集它 然后我在流

  • 问题内容: 假设两个类为ClassA和ClassB。假设ClassB依赖于ClassA。在配置文件中,如果将ClassA的范围定义为单例,将ClassB的范围定义为Prototype,那么每次创建ClassA的bean实例时,ClassB的实例会发生什么?每次返回ClassA实例时,将返回相同的ClassB实例还是创建新实例? 谢谢!!! 问题答案: 如果ClassB是原型,则始终创建ClassB

  • 我有一个带有@service和@Scope(“原型”)的服务类。我希望此服务的行为类似于控制器类中的原型。以下是我如何使用它: 以下是服务类别: 我使用自动配置属性运行spring boot。我比较“emailService”对象是否相同,得到的是相同的一个对象。这意味着@Scope(“prototype”)不能像预期的那样与@Service一起工作。你看到这里有什么问题吗?我忘了添加一些代码了吗

  • 在方括号 […] 中的几个字符或者字符类意味着“搜索给定的字符中的任意一个”。 集合 比如说,[eao] 意味着查找在 3 个字符 'a'、'e' 或者 `‘o’ 中的任意一个。 这被叫做一个集合。集合可以在正则表达式中和其它常规字符一起使用。 // 查找 [t 或者 m],然后再匹配 “op” alert( "Mop top".match(/[tm]op/gi) ); // "Mop", "to