【问题标题】:Spring - How to choose properties in dependent bean?Spring - 如何在依赖 bean 中选择属性?
【发布时间】:2013-09-24 10:52:59
【问题描述】:

假设,我的 Spring xml 中有以下 bean:

<bean id="mqConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
    <property name="hostName" value="${host}"/>
    <property name="port" value="${mq.port}"/>
</bean>

<bean id="jmsQueueConnectionFactory"
      class="org.springframework.jms.connection.SingleConnectionFactory">
    <property name="targetConnectionFactory" ref="mqConnectionFactory"/>
</bean>

<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory" ref="jmsQueueConnectionFactory"/>
</bean>

我需要向不同的主机发送消息,但我不想定义多个连接工厂 bean。

这样指定主机会很棒:

class A {
    @Autowired(host="host1")
    private JmsTemplate jmsTemplate;
}

class B {
    @Autowired(host="host2")
    private JmsTemplate jmsTemplate;
}

更新:

我可以创建以下配置:

<bean id="mqConnectionFactory1" class="com.ibm.mq.jms.MQQueueConnectionFactory">
    <property name="hostName" value="${host1}"/>
    <property name="port" value="${mq.port}"/>
</bean>

<bean id="mqConnectionFactory2" class="com.ibm.mq.jms.MQQueueConnectionFactory">
    <property name="hostName" value="${host2}"/>
    <property name="port" value="${mq.port}"/>
</bean>

<bean id="jmsQueueConnectionFactory1"
      class="org.springframework.jms.connection.SingleConnectionFactory">
    <property name="targetConnectionFactory" ref="mqConnectionFactory1"/>
</bean>

<bean id="jmsQueueConnectionFactory2"
      class="org.springframework.jms.connection.SingleConnectionFactory">
    <property name="targetConnectionFactory" ref="mqConnectionFactory2"/>
</bean>

<bean id="jmsTemplate1" class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory" ref="jmsQueueConnectionFactory1"/>
</bean>

<bean id="jmsTemplate2" class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory" ref="jmsQueueConnectionFactory2"/>
</bean>

然后:

class A {
    @Resource("jmsTemplate1")
    private JmsTemplate jmsTemplate;
}

class B {
    @Resource("jmsTemplate2")
    private JmsTemplate jmsTemplate;
}

这似乎是错误和复杂的。问题是减少此配置并将主机作为参数传递。换句话说,我想告诉 Spring:“创建我 jmsTemplate 并将 connectionFactory 的属性主机设置为此值。”

【问题讨论】:

    标签: java spring inversion-of-control


    【解决方案1】:

    您的提议的问题在于 JMS 连接器是一个单例,这意味着它在您的应用程序中的所有对象/线程之间共享。因此,在一个对象/线程中更改其主机配置会导致使用它的其他对象/线程出现问题。

    我的建议是您使用 spring bean“父级”(参见 *1)来定义到每个适用主机的不同 jms 连接,然后使用 @Resource 而不是 autowire(或 @Autowire @Qualifier 组合来强制豆见*2)

    编辑:另一种可能的解决方案是使用 FactoryBean(s),尽管我不能 100% 确定语法。

    *1 http://www.mkyong.com/spring/spring-bean-configuration-inheritance/

    *2 Autowiring spring bean by name using annotation

    【讨论】:

    • 我知道@Resource 注解和bean 继承,但它不适合我。看来我需要一个工厂,它接受主机参数并用相应的连接工厂构造 jmsTemplate。我会试试 FactoryBean。谢谢!
    • 正如我在回答中所说的那样。 JMS 连接器必须是单例的,否则每次需要初始化每个连接时,您都会冒巨大的性能损失风险。您可能想为您的工厂添加缓存。
    • 如果我没有遗漏什么,我可以告诉 Spring 将连接工厂设为单例,以共享(在我的情况下)一个物理连接。
    【解决方案2】:

    这就是我的工作:

    我有不同的属性文件,其中包含不同环境(如本地、开发和生产)的连接信息。

    • db.local.properties
    • db.dev.properties
    • db.prod.properties

    通过设置环境变量运行我的应用程序时,我只使用了其中一个属性文件:

    <bean id="dbPlaceholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
       <property name="location" value="classpath:db.${db.environment:dev}.properties"/>
    </bean>
    

    在这里您可以看到我使用了一个名为 {db.environment} 的环境变量,如果未定义该值,则默认为 dev 形成文件名 db.dev.properties

    我的下一步是在我运行应用程序的不同环境中定义变量

    java -Ddb.environenment=prod ...
    

    由于我使用的是 Tomcat,我在 sentenv.sh 中定义了该变量,但我很确定其他应用程序服务器提供了类似的机制。

    然后我的代码使用属性文件提供的参数

    @Value("${db.url}")
    private String databaseUrl;
    @Value("${db.userName}")
    private String userName;
    @Value("${db.password}")
    private String password;
    

    【讨论】:

    • 看来很有用,这个技巧我会记住的。但就我而言,班级必须决定向哪个主机发送消息。在某些情况下,它会使用两个目的地。
    • 我明白了,我以为您的问题是关于环境问题,而不是您实际上同时使用了两台服务器。如果是这种情况,我不明白你为什么想要一个连接,如果你说你可能需要两个。
    • 当然,我需要多个连接。我不想像 mqConnectionFactoryHost1、mqConnectionFactoryHost2、jmsTemplateHost1、jmsTemplateHost2 那样复制这个配置。我需要在创建 jmsTemplate 期间指定主机。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-19
    • 2018-02-08
    • 2012-08-02
    • 1970-01-01
    • 2011-07-22
    相关资源
    最近更新 更多