使用 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
我想使用 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