Пользователь Spring JMS HornetQ является нулевым - PullRequest
0 голосов
/ 01 января 2019

Я пытаюсь подключиться к удаленному брокеру HornetQ в приложении Spring Boot / Spring JMS и настроить @JmsListener.

HornetQ ConnectionFactory извлекается из реестра JNDI, в котором находятся экземпляры HornetQ.Все работает нормально, пока защита HornetQ выключена, но когда она включена, я получаю эту ошибку

WARN  o.s.j.l.DefaultMessageListenerContainer : Setup of JMS message listener invoker failed for destination 'jms/MI/Notification/Queue' - trying to recover. Cause: User: null doesn't have permission='CONSUME' on address jms.queue.MI/Notification/Queue

Я запустил сеанс отладки, чтобы выяснить, что возвращаемый экземпляр ConnectionFactory равен HornetQXAConnectionFactory, нополя user и password не установлены, поэтому я считаю, что user имеет значение null.Я проверил, что основной пользователь и учетные данные установлены в свойствах JNDI, но каким-то образом он не передается экземпляру ConnectionFactory.Буду очень признателен за любую помощь в том, как я могу настроить эту настройку.

Это моя конфигурация, связанная с jms

@Configuration
@EnableJms
public class JmsConfig {

    @Bean
    public JmsListenerContainerFactory<?> jmsListenerContainerFactory(ConnectionFactory connectionFactory,
            DefaultJmsListenerContainerFactoryConfigurer configurer) {
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();

        configurer.configure(factory, connectionFactory);

        factory.setDestinationResolver(destinationResolver());
        return factory;
    }

    @Bean // Serialize message content to json using TextMessage
    public MessageConverter jacksonJmsMessageConverter() {
        MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
        converter.setTargetType(MessageType.BYTES);
        converter.setTypeIdPropertyName("_type");
        return converter;
    }

    @Value("${jms.jndi.provider.url}")
    private String jndiProviderURL;
    @Value("${jms.jndi.principal}")
    private String jndiPrincipal;
    @Value("${jms.jndi.credentials}")
    private String jndiCredential;

    @Bean
    public JndiTemplate jndiTemplate() {
        Properties env = new Properties();
        env.put("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
        env.put("java.naming.provider.url", jndiProviderURL);
        env.put("java.naming.security.principal", jndiPrincipal);
        env.put("java.naming.security.credentials", jndiCredential);
        return new JndiTemplate(env);
    }
    @Bean
    public DestinationResolver destinationResolver() {
        JndiDestinationResolver destinationResolver = new JndiDestinationResolver();
        destinationResolver.setJndiTemplate(jndiTemplate());
        return destinationResolver;
    }

    @Value("${jms.connectionfactory.jndiname}")
    private String connectionFactoryJNDIName;

    @Bean
    public JndiObjectFactoryBean connectionFactoryFactory() {
        JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean();
        jndiObjectFactoryBean.setJndiTemplate(jndiTemplate());
        jndiObjectFactoryBean.setJndiName(connectionFactoryJNDIName);
        jndiObjectFactoryBean.setResourceRef(true);
        jndiObjectFactoryBean.setProxyInterface(ConnectionFactory.class);
        return jndiObjectFactoryBean;
    }

    @Bean
    public ConnectionFactory connectionFactory(JndiObjectFactoryBean connectionFactoryFactory) {
        return (ConnectionFactory) connectionFactoryFactory.getObject();
    }
}

Ответы [ 2 ]

0 голосов
/ 01 января 2019

Заверните фабрику соединений в UserCredentialsConnectionFactoryAdapter.

/**
 * An adapter for a target JMS {@link javax.jms.ConnectionFactory}, applying the
 * given user credentials to every standard {@code createConnection()} call,
 * that is, implicitly invoking {@code createConnection(username, password)}
 * on the target. All other methods simply delegate to the corresponding methods
 * of the target ConnectionFactory.
 * ...
0 голосов
/ 01 января 2019

JNDI и JMS на 100% независимы, поскольку они представляют собой совершенно разные спецификации, реализованные потенциально совершенно разными способами.Поэтому учетные данные, которые вы используете для поиска JNDI, не применяются к вашим ресурсам JMS.Вам необходимо явно установить учетные данные для имени пользователя и пароля в вашем JMS-соединении.Это легко с помощью JMS API напрямую (например, через javax.jms.ConnectionFactory#createConnection(String username, String password)).Поскольку вы используете Spring, вы можете использовать что-то вроде этого:

@Bean
public ConnectionFactory connectionFactory(JndiObjectFactoryBean connectionFactoryFactory) {
    UserCredentialsConnectionFactoryAdapter cf = new UserCredentialsConnectionFactoryAdapter();
    cf.setTargetConnectionFactory((ConnectionFactory) connectionFactoryFactory.getObject());
    cf.setUsername("yourJmsUsername");
    cf.setPassword("yourJmsPassword");
    return cf;
}

Кроме того, за все, что стоит, кодовая база HornetQ была пожертвована проекту Apache ActiveMQ три иПолтора года назад, и он продолжает работать как Apache ActiveMQ Artemis брокер.С тех пор было 22 релиза с многочисленными новыми функциями и исправлениями ошибок.Я настоятельно рекомендую вам перенести, если это вообще возможно.

...