本文介绍了执行器JMS运行状况检查通过Java配置返回假肯定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了一个问题,即使我的路由可以连接并向JMS生成消息,但对于JMS运行状况来说,执行器探针仍会失败.简而言之,Actuator表示它已关闭但正在运行.

技术堆栈和技术说明:

  • 春季启动:2.3.1.发布
  • 骆驼:3.4.1
  • Artemis:2.11.0
  • Artemis已设置为使用用户名和密码(artemis/artemis).
  • org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory用于连接工厂.

我的路线就像筹码一样简单:

  <route id="timer-cluster-producer-route">
            <from uri="timer:producer-ticker?delay=5000"/>

            <setBody>
                <groovy>
                    result = ["Name":"Johnny"]
                </groovy>
            </setBody>
            <marshal>
                <json library="Jackson"/>
            </marshal>
            <to uri="ref:jms-producer-cluster-event" />
   </route>

基于XML的Artemis配置

使用Spring-boot支持基于Java的配置时,我正忙于相应地迁移XML bean.因此,我将一个有效的bean.xml文件粘贴到项目中并启动了路由,我可以发送消息并运行状况检查返回OK


<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
         http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
    <bean id="jmsConnectionFactory"
        class="org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory">
        <property name="brokerURL" value="tcp://localhost:61616" />
        <property name="user" value="artemis"/>
        <property name="password" value="artemis"/>
        <property name="connectionLoadBalancingPolicyClassName" value="org.apache.activemq.artemis.api.core.client.loadbalance.RoundRobinConnectionLoadBalancingPolicy"/>
    </bean>
    <!--org.messaginghub.pooled.jms.JmsPoolConnectionFactory-->
    <!--org.apache.activemq.jms.pool.PooledConnectionFactory-->
    <bean id="jmsPooledConnectionFactory"
        class="org.apache.activemq.jms.pool.PooledConnectionFactory"
        init-method="start" destroy-method="stop">
        <property name="maxConnections" value="64" />
        <property name="MaximumActiveSessionPerConnection"
            value="500" />
        <property name="connectionFactory" ref="jmsConnectionFactory" />
    </bean>
    <bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">
        <property name="connectionFactory"
            ref="jmsPooledConnectionFactory" />
        <property name="concurrentConsumers" value="1" />
        <property name="artemisStreamingEnabled" value="true"/>
    </bean>
    <bean id="jms"
          class="org.apache.camel.component.jms.JmsComponent">
        <property name="configuration" ref="jmsConfig"/>

    </bean>

<!--    <bean id="activemq"
        class="org.apache.activemq.camel.component.ActiveMQComponent">
        <property name="configuration" ref="jmsConfig" />
    </bean>-->


</beans>


春季启动自动(黑色)魔术配置

然后我使用此方法,如Spring-boot文档中所述.当我的application.yaml文件包含以下配置时,此方法也起作用:

artemis:
  user: artemis
  host: localhost
  password: artemis
  pool:
    max-sessions-per-connection: 500
    enabled: true
    max-connections: 16

这就像一种魅力.

勇敢尝试Java配置.

所以我接着去淘金,尝试了如下所示的基于Java的配置:

@SpringBootApplication
@ImportResource("classpath:/camel/camel.xml")
public class ClusterProducerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ClusterProducerApplication.class, args);
    }
    @Bean
    public JmsComponent jms() throws JMSException {
        // Create the connectionfactory which will be used to connect to Artemis
        ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory();
        cf.setBrokerURL("tcp://localhost:61616");
        cf.setUser("artemis");
        cf.setPassword("artemis");

        //Create connection pool using connection factory
        PooledConnectionFactory pooledConnectionFactory = new PooledConnectionFactory();
        pooledConnectionFactory.setMaxConnections(2);
        pooledConnectionFactory.setConnectionFactory(cf);

        //Create configuration which uses connection factory
        JmsConfiguration jmsConfiguration = new JmsConfiguration();
        jmsConfiguration.setConcurrentConsumers(2);
        jmsConfiguration.setArtemisStreamingEnabled(true);
        jmsConfiguration.setConnectionFactory(pooledConnectionFactory);

        // Create the Camel JMS component and wire it to our Artemis configuration
        JmsComponent jms = new JmsComponent();
        jms.setConfiguration(jmsConfiguration);
        return jms;
    }
}

因此,当骆驼启动时,我会在启动时看到以下警告:

020-07-28 12:33:38.631  WARN 25329 --- [)-192.168.1.158] o.s.boot.actuate.jms.JmsHealthIndicator  : JMS health check failed

javax.jms.JMSSecurityException: AMQ229031: Unable to validate user from /127.0.0.1:42028. Username: null; SSL certificate subject DN: unavailable

5秒延迟后,计时器开始计时并生成消息.我登录到Artemis控制台,可以浏览消息并看到它们正在创建.但是,当我对执行器的运行状况进行检查时,会看到以下内容:

 "jms": {
            "status": "DOWN",
            "details": {
                "error": "javax.jms.JMSSecurityException: AMQ229031: Unable to validate user from /127.0.0.1:42816. Username: null; SSL certificate subject DN: unavailable"
            }
        },

这对我来说似乎是个很大的错误.

有关连接池实现的观察.

我注意到AMQ连接池已移入以下Maven依赖项:

<dependency>
  <groupId>org.messaginghub</groupId>
  <artifactId>pooled-jms</artifactId>
</dependency>

我想让我也尝试一下.它显示了与上面概述的行为相同的行为,还有另外一件有趣的事情.当使用org.messaginghub.pooled-jms作为连接池时(同样由spring-boot docs推荐),以下内容将在启动时记录.

2020-07-28 12:41:37.255  INFO 26668 --- [           main] o.m.pooled.jms.JmsPoolConnectionFactory  : JMS ConnectionFactory on classpath is not a JMS 2.0+ version.

根据官方仓库,该连接器符合JMS 2.0标准./p>

快速摘要:通过Java配置JMS组件时,执行器似乎没有获取连接工厂的凭据.通过使用spring-boot application.yaml配置,目前可以解决此问题,但它限制了您在Camel上配置JMS客户端的方式.

解决方案

因此,在对GitHub上的Spring-boot人员进行了深入挖掘并与他们联系之后,我发现了问题所在.使用Java配置时,我正在使用连接工厂配置Camel的JMS组件.但是,Spring-boot完全没有意识到这一点,因为它是Camel组件.因此,JMS使用的连接工厂需要暴露于Spring-boot才能正常工作.

修复相对简单.参见下面的代码:

@Configuration
public class ApplicationConfiguration {
    private ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory();
    @Bean
    public JmsComponent jms() throws JMSException {
        // Create the connectionfactory which will be used to connect to Artemis
        cf.setBrokerURL("tcp://localhost:61616");
        cf.setUser("artemis");
        cf.setPassword("artemis");

        // Setup Connection pooling
        PooledConnectionFactory pooledConnectionFactory = new PooledConnectionFactory();
        pooledConnectionFactory.setMaxConnections(2);
        pooledConnectionFactory.setConnectionFactory(cf);
        JmsConfiguration jmsConfiguration = new JmsConfiguration();
        jmsConfiguration.setConcurrentConsumers(2);
        jmsConfiguration.setArtemisStreamingEnabled(true);
        jmsConfiguration.setConnectionFactory(pooledConnectionFactory);
        // Create the Camel JMS component and wire it to our Artemis connectionfactory
        JmsComponent jms = new JmsComponent();
        jms.setConfiguration(jmsConfiguration);
        return jms;
    }
    /*
       This line will expose the connection factory to Spring-boot.
    */
    @Bean
    public ConnectionFactory jmsConnectionFactory() {
        return cf;
    }
}

I have run into an issue where the Actuator probe fails for JMS health even though my routes can connect and produce message to JMS. So in short Actuator is saying it is down but it is working.

Tech stack and tech notes:

  • Spring-boot: 2.3.1.RELEASE
  • Camel: 3.4.1
  • Artemis: 2.11.0
  • Artemis has been setup to use a user name and password(artemis/artemis).
  • Using org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory for connection factory.

My route is as simple as chips:

  <route id="timer-cluster-producer-route">
            <from uri="timer:producer-ticker?delay=5000"/>

            <setBody>
                <groovy>
                    result = ["Name":"Johnny"]
                </groovy>
            </setBody>
            <marshal>
                <json library="Jackson"/>
            </marshal>
            <to uri="ref:jms-producer-cluster-event" />
   </route>

XML Based Artemis Configuration

With Spring-boot favoring java based configuration I am busy migrating our XML beans accordingly.Thus I took a working beans.xml file pasted into the project and fired up the route and I could send messages flowing and the health check returned OK.


<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
         http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
    <bean id="jmsConnectionFactory"
        class="org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory">
        <property name="brokerURL" value="tcp://localhost:61616" />
        <property name="user" value="artemis"/>
        <property name="password" value="artemis"/>
        <property name="connectionLoadBalancingPolicyClassName" value="org.apache.activemq.artemis.api.core.client.loadbalance.RoundRobinConnectionLoadBalancingPolicy"/>
    </bean>
    <!--org.messaginghub.pooled.jms.JmsPoolConnectionFactory-->
    <!--org.apache.activemq.jms.pool.PooledConnectionFactory-->
    <bean id="jmsPooledConnectionFactory"
        class="org.apache.activemq.jms.pool.PooledConnectionFactory"
        init-method="start" destroy-method="stop">
        <property name="maxConnections" value="64" />
        <property name="MaximumActiveSessionPerConnection"
            value="500" />
        <property name="connectionFactory" ref="jmsConnectionFactory" />
    </bean>
    <bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">
        <property name="connectionFactory"
            ref="jmsPooledConnectionFactory" />
        <property name="concurrentConsumers" value="1" />
        <property name="artemisStreamingEnabled" value="true"/>
    </bean>
    <bean id="jms"
          class="org.apache.camel.component.jms.JmsComponent">
        <property name="configuration" ref="jmsConfig"/>

    </bean>

<!--    <bean id="activemq"
        class="org.apache.activemq.camel.component.ActiveMQComponent">
        <property name="configuration" ref="jmsConfig" />
    </bean>-->


</beans>


Spring-boot Auto (Black)Magic Configuration

I then used the application.yaml file to configure the artemis connection by using this method as outlined in the Spring-boot documentation. This also worked when my application.yaml file contained the following configuration:

artemis:
  user: artemis
  host: localhost
  password: artemis
  pool:
    max-sessions-per-connection: 500
    enabled: true
    max-connections: 16

This worked like a charm.

Brave Attempt At Java Configuration.

So I then went for gold and tried the Java based configuration as outlined below:

@SpringBootApplication
@ImportResource("classpath:/camel/camel.xml")
public class ClusterProducerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ClusterProducerApplication.class, args);
    }
    @Bean
    public JmsComponent jms() throws JMSException {
        // Create the connectionfactory which will be used to connect to Artemis
        ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory();
        cf.setBrokerURL("tcp://localhost:61616");
        cf.setUser("artemis");
        cf.setPassword("artemis");

        //Create connection pool using connection factory
        PooledConnectionFactory pooledConnectionFactory = new PooledConnectionFactory();
        pooledConnectionFactory.setMaxConnections(2);
        pooledConnectionFactory.setConnectionFactory(cf);

        //Create configuration which uses connection factory
        JmsConfiguration jmsConfiguration = new JmsConfiguration();
        jmsConfiguration.setConcurrentConsumers(2);
        jmsConfiguration.setArtemisStreamingEnabled(true);
        jmsConfiguration.setConnectionFactory(pooledConnectionFactory);

        // Create the Camel JMS component and wire it to our Artemis configuration
        JmsComponent jms = new JmsComponent();
        jms.setConfiguration(jmsConfiguration);
        return jms;
    }
}

So when camel starts up I see the following warning logged on start up:

020-07-28 12:33:38.631  WARN 25329 --- [)-192.168.1.158] o.s.boot.actuate.jms.JmsHealthIndicator  : JMS health check failed

javax.jms.JMSSecurityException: AMQ229031: Unable to validate user from /127.0.0.1:42028. Username: null; SSL certificate subject DN: unavailable

After the 5sec delay the timer kicks in and message are being produced. I logged into the Artemis console and I can browse the messages and can see them being created. However when I run a get on actuator health I see the following:

 "jms": {
            "status": "DOWN",
            "details": {
                "error": "javax.jms.JMSSecurityException: AMQ229031: Unable to validate user from /127.0.0.1:42816. Username: null; SSL certificate subject DN: unavailable"
            }
        },

This feels like a big of a bug to me.

Observations about connection pooling implementations.

I noticed that AMQ connection pooling has been moved into the following maven dependency:

<dependency>
  <groupId>org.messaginghub</groupId>
  <artifactId>pooled-jms</artifactId>
</dependency>

I thought let me give that a try as well. It show the same behaviour as outlined above with one more interesting thing. When using org.messaginghub.pooled-jms as the connection pool(recommended by spring-boot docs as well) the following is logged on startup.

2020-07-28 12:41:37.255  INFO 26668 --- [           main] o.m.pooled.jms.JmsPoolConnectionFactory  : JMS ConnectionFactory on classpath is not a JMS 2.0+ version.

Which is weird as according to the official repo the connector is JMS 2.0 compliant.

Quick Summary:It appears that actuator does not pick up the credentials of the connection factory when configuring the JMS component via Java. While a work around exists at the moment by using the spring-boot application.yaml configuration it limits the way you can configure JMS clients on Camel.

解决方案

So after some digging and reaching out to the Spring-boot people on GitHub I found what the issue is. When using Java configuration I am configuring the JMS component of Camel with a connection factory. However Spring-boot is completely unaware of this as it is a Camel component. Thus the connection factory used by the JMS needs to be exposed to Spring-boot for it to work.

The fix is relatively simple. See code below:

@Configuration
public class ApplicationConfiguration {
    private ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory();
    @Bean
    public JmsComponent jms() throws JMSException {
        // Create the connectionfactory which will be used to connect to Artemis
        cf.setBrokerURL("tcp://localhost:61616");
        cf.setUser("artemis");
        cf.setPassword("artemis");

        // Setup Connection pooling
        PooledConnectionFactory pooledConnectionFactory = new PooledConnectionFactory();
        pooledConnectionFactory.setMaxConnections(2);
        pooledConnectionFactory.setConnectionFactory(cf);
        JmsConfiguration jmsConfiguration = new JmsConfiguration();
        jmsConfiguration.setConcurrentConsumers(2);
        jmsConfiguration.setArtemisStreamingEnabled(true);
        jmsConfiguration.setConnectionFactory(pooledConnectionFactory);
        // Create the Camel JMS component and wire it to our Artemis connectionfactory
        JmsComponent jms = new JmsComponent();
        jms.setConfiguration(jmsConfiguration);
        return jms;
    }
    /*
       This line will expose the connection factory to Spring-boot.
    */
    @Bean
    public ConnectionFactory jmsConnectionFactory() {
        return cf;
    }
}

这篇关于执行器JMS运行状况检查通过Java配置返回假肯定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-12 18:03