【问题标题】:Retrive JMS ConnectionFactory from JNDI using Spring Boot auto-configuration使用 Spring Boot 自动配置从 JNDI 中检索 JMS ConnectionFactory
【发布时间】:2019-08-24 08:23:26
【问题描述】:

我想使用 JMS 的 spring boot 自动配置连接到远程 JNDI 并根据通过 spring.jms.jndi-name填充的他的名字检索 ConnectionFactory > application.properties 文件中的属性。

我注意到 Spring Boot 自动配置依赖于 JndiConnectionFactoryAutoConfiguration 类来执行此操作,而该类又会调用 JndiTemplate 类来进行查找。问题是JndiTemplate类的environment属性的值为null,所以无法创建intialContext。

事实上,我注意到 JndiTemplate 类在启动应用程序时和加载 JndiConnectionFactoryAutoConfiguration 类中定义的配置之前使用无参数构造函数进行实例化。

我的问题:如何通过指定属性列表(Context.INITIAL_CONTEXT_FACTORY、Context.PROVIDER_URL..)来实例化 JndiTemplate?知道 JmsTemplate 有一个接受 Properties 对象的构造函数。

仅供参考:我的应用程序是一个简单的 jar,目前不在服务器上运行。

【问题讨论】:

  • 昨天这里没有答案吗 :)
  • 我发布答案;)

标签: spring spring-boot jms jndi spring-jms


【解决方案1】:

对于那些对答案感兴趣的人,您必须使用 VM 选项来传递所需的 JNDI 属性。

这是一个与 ActiveMQ 一起使用的示例:

虚拟机选项:

-Djava.naming.provider.url=tcp://hostname:61616

-Djava.naming.factory.initial=org.apache.activemq.jndi.ActiveMQInitialContextFactory

并且spring属性文件(application.properties)必须包含连接工厂的JNDI名称:

spring.jms.jndi-name=ConnectionFactory

更好的是,您可以使用配置从 JNDI 中找到您的连接工厂。在我的项目中,我们完成了创建可以在所有微服务中使用的 jms 启动器。

属性类:

import lombok.*;
import org.springframework.boot.context.properties.ConfigurationProperties;


@Getter
@Setter
@ToString
@NoArgsConstructor
@EqualsAndHashCode
@ConfigurationProperties( prefix = "custom.jms" )
public class CustomJmsProperties {
    private String jndiName;
    private String contextFactoryClass;
    private String providerUrl;
    private String username;
    private String password;
}

配置类:

import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter;
import org.springframework.jndi.JndiLocatorDelegate;

import javax.jms.ConnectionFactory;
import javax.naming.Context;
import javax.naming.NamingException;
import java.util.Properties;

@Configuration
@ConditionalOnProperty( "custom.jms.jndi-name" )
@ConditionalOnMissingBean( ConnectionFactory.class )
@EnableConfigurationProperties( { CustomJmsProperties.class } )
@AutoConfigureAfter( { JndiConnectionFactoryAutoConfiguration.class } )
public class CustomJndiConnectionFactoryAutoConfiguration {

    @Bean
    public ConnectionFactory connectionFactory( CustomJmsProperties customJmsProperties ) throws NamingException {
        ConnectionFactory connectionFactory = lookupForConnectionFactory( customJmsProperties );
        return getEnhancedUserCredentialsConnectionFactory( customJmsProperties, connectionFactory );
    }

    private ConnectionFactory lookupForConnectionFactory( final CustomJmsProperties customJmsProperties ) throws NamingException {
        JndiLocatorDelegate jndiLocatorDelegate = new JndiLocatorDelegate();
        Properties jndiProperties = getJndiProperties( customJmsProperties );
        jndiLocatorDelegate.setJndiEnvironment( jndiProperties );
        return jndiLocatorDelegate.lookup( customJmsProperties.getJndiName(), ConnectionFactory.class );
    }

    private Properties getJndiProperties( final CustomJmsProperties customJmsProperties ) {
        Properties jndiProperties = new Properties();
        jndiProperties.setProperty( Context.PROVIDER_URL, customJmsProperties.getProviderUrl() );
        jndiProperties.setProperty( Context.INITIAL_CONTEXT_FACTORY, customJmsProperties.getContextFactoryClass() );
        if ( StringUtils.isNotEmpty( customJmsProperties.getUsername() ) ) {
            jndiProperties.setProperty( Context.SECURITY_PRINCIPAL, customJmsProperties.getUsername() );
        }
        if ( StringUtils.isNotEmpty( customJmsProperties.getPassword() ) ) {
            jndiProperties.setProperty( Context.SECURITY_CREDENTIALS, customJmsProperties.getPassword() );
        }
        return jndiProperties;
    }

    private UserCredentialsConnectionFactoryAdapter getEnhancedUserCredentialsConnectionFactory( final CustomJmsProperties customJmsProperties,
                                                                                                 final ConnectionFactory connectionFactory ) {
        UserCredentialsConnectionFactoryAdapter enhancedConnectionFactory = new UserCredentialsConnectionFactoryAdapter();
        enhancedConnectionFactory.setTargetConnectionFactory( connectionFactory );
        enhancedConnectionFactory.setUsername( customJmsProperties.getUsername() );
        enhancedConnectionFactory.setPassword( customJmsProperties.getPassword() );
        enhancedConnectionFactory.afterPropertiesSet();
        return enhancedConnectionFactory;
    }
}

项目的属性文件:

custom.jms.provider-url=tcp://hostname:61616
custom.jms.context-factory-class=org.apache.activemq.jndi.ActiveMQInitialContextFactory
custom.jms.jndi-name=ConnectionFactory

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-24
    • 2016-01-21
    • 1970-01-01
    • 1970-01-01
    • 2019-05-19
    • 2016-06-12
    • 2015-07-24
    • 2017-01-31
    相关资源
    最近更新 更多