使用 Spring 引导自动配置从 JNDI 检索 JMS ConnectionFactory

Retrive JMS ConnectionFactory from JNDI using Spring Boot auto-configuration

我想使用 JMS 的 spring 引导自动配置连接到远程 JNDI 并检索 ConnectionFactory 基于通过 spring.jms.jndi-name 属性 在 application.properties 文件中。

我注意到 spring 引导自动配置依赖于 JndiConnectionFactoryAutoConfiguration class 来执行此操作,而此 class 又会调用JndiTemplate class 进行查找。问题是 JndiTemplate class 的环境属性值为 null,所以我们无法创建 intialContext。

事实上,我注意到 JndiTemplate class 在启动应用程序和加载 [=21= 中定义的配置之前使用无参数构造函数实例化]JndiConnectionFactoryAutoConfiguration class.

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

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

对于那些对答案感兴趣的人,您必须使用 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 启动器来完成。

属性class:

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;
}

配置class:

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