#spring #spring-boot #jms #jndi #spring-jms
#spring #spring-boot #jms #jndi #spring-jms
Вопрос:
Я хочу использовать автоконфигурацию spring boot для JMS для подключения к удаленному JNDI и получить ConnectionFactory на основе его имени, заполненного через свойство spring.jms.jndi-name в файле application.properties.
Я заметил, что для этого автоконфигурация spring boot полагается на класс JndiConnectionFactoryAutoConfiguration, а этот класс, в свою очередь, вызовет класс JndiTemplate для выполнения поиска. Проблема в том, что значение атрибута среды класса JndiTemplate равно null, поэтому мы не можем создать intialContext.
На самом деле, я заметил, что класс JndiTemplate создается с помощью конструктора без аргументов при запуске приложения и перед загрузкой конфигурации, определенной в классе JndiConnectionFactoryAutoConfiguration.
Мой вопрос: как я могу создать экземпляр JndiTemplate, указав список свойств (Context.INITIAL_CONTEXT_FACTORY, контекст.PROVIDER_URL..)? зная, что у JmsTemplate есть конструктор, который принимает объект свойств.
Просто для информации: мое приложение представляет собой простой jar, который в данный момент не запускается на сервере.
Комментарии:
1. разве вчера здесь не было ответа 🙂
2. Я публикую ответ;)
Ответ №1:
Для тех, кого интересует ответ, вы должны использовать параметры виртуальной машины для передачи требуемых свойств 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 starter, который мы можем использовать во всех микросервисах.
Класс свойств:
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