十四、Spring cloud消息驱动整合(activemq)

一、安装 activemq

1、去linux官网下载
wget ****

2、解压
tar -zxvf apache-activemq-5.14.0-bin.tar.gz

3、启动

./activemq start

关闭:./activemq stop

4、开启防火墙端口
(1)如果使用了云服务器需要先开启8161(web管理页面端口)、61616(activemq服务监控端口) 两个端口
(2)打开linux防火墙端口

/sbin/iptables -I INPUT -p tcp --dport 8161 -j ACCEPT&&/etc/init.d/iptables save&&service iptables restart&&/etc/init.d/iptables status
/sbin/iptables -I INPUT -p tcp --dport 61616 -j ACCEPT&&/etc/init.d/iptables save&&service iptables restart&&/etc/init.d/iptables status

5、打开web管理页面
http://IP:8161/admin
默认用户名密码 admin/admin

二、Spring Cloud Stream Binder实现

(一)JMS 实现 ActiveMQ(原生API)

1、增加依赖

<!-- 整合 activemq:
             间接依赖:
             spring jms
             jms api
             activemq
             spring boot jms
         -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-activemq</artifactId>
        </dependency>

2、启动 ActiveMQ Broker

./activemq start

3、原生API:生产、消费消息

  请注意在启动 ActiveMQ 之后控制台输出:

 INFO | Listening for connections at: tcp://administrator:61616?
 maximumConnections=1000&wireFormat.maxFrameSize=104857600

  其中 tcp://administrator:61616 就是 brokerURL,请注意将主机名转换成IP:tcp://192.168.10.130:61616

(1)原生API:生产消息

/**
     * 生产消息
     */
    private static void sendMessage() throws JMSException {
        //1、创建 ActiveMQ 连接,设置 brokerURL
        ConnectionFactory connectionFactory =
                new ActiveMQConnectionFactory("tcp://192.168.10.130:61616");

        //2、创建 JMS 连接
        Connection connection = connectionFactory.createConnection();

        //3、创建会话 Session(参数一 transacted:是否是事务  参数二:自动确认)
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

        /**
         * 4、创建消息目的:
         * 第一种 Queue:点对点消息
         * 第二种 Topic:广播式消息
         */
        Destination destination = session.createQueue("test");

        //5、创建消息生产者
        MessageProducer messageProducer = session.createProducer(destination);

        //6、创建消息 - 文本消息
        ActiveMQTextMessage message = new ActiveMQTextMessage();
        message.setText("how are you?");
        //7、发送文本消息
        messageProducer.send(message);

        //8、关闭消息发送者、Session、Connection
        messageProducer.close();
        session.close();
        connection.close();
    }

(2)原生API:消费消息

/**
     * 消费消息
     */
    private static void consumeMessage() throws JMSException {
        //1、创建 ActiveMQ 连接,设置 brokerURL
        ConnectionFactory connectionFactory =
                new ActiveMQConnectionFactory("tcp://192.168.10.130:61616");

        //2、创建 JMS 连接
        Connection connection = connectionFactory.createConnection();

        //3、启动连接(这里需要手动启动)
        connection.start();

        //4、创建会话 Session(参数一 transacted:是否是事务  参数二:自动确认)
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

        /**
         * 5、创建消息目的:
         * 第一种 Queue:点对点消息
         * 第二种 Topic:广播式消息
         */
        Destination destination = session.createQueue("test");

        //6、创建消费者
        MessageConsumer consumer = session.createConsumer(destination);

        //7、获取消息
        Message message = consumer.receive(100);

        if (message instanceof TextMessage) {
            TextMessage textMessage = (TextMessage) message;
            System.out.println("----------------------------------");
            System.out.println("消费消息:" + textMessage.getText());
        }

        //8、关闭消息发送者、Session、Connection
        consumer.close();
        session.close();
        connection.close();
    }

(二)Spring Boot + ActiveMQ

1、改造消息发送者:user-service-client 应用

(1)增加依赖

		<!-- 整合 activemq:
                 间接依赖:
                 spring jms
                 jms api
                 activemq
                 spring boot jms
             -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-activemq</artifactId>
            </dependency>

(2)配置 ActiveMQ 属性

#配置 ActiveMQ 属性
spring.activemq.broker-url=tcp://192.168.10.130:61616

(3)配置 JMS 属性(消息目的地)

#配置 JMS 属性(消息目的地)
spring.jms.template.default-destination=custom-destination

(4)实现 User 对象 消息发送

	@Autowired
    private JmsTemplate jmsTemplate;

    @PostMapping("/user/save/message/activemq")
    public boolean saveUserByActiveMQ(@RequestBody User user) throws IOException {
        //发送消息到 ActiveMQ
        jmsTemplate.convertAndSend(user);

        return true;
    }

2、改造消息 消费者:user-service-provider 应用

(1)增加依赖

<!-- 整合 activemq:
                 间接依赖:
                 spring jms
                 jms api
                 activemq
                 spring boot jms
             -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-activemq</artifactId>
            </dependency>

(2)配置 ActiveMQ 和 JMS 属性

#配置 ActiveMQ 属性
spring.activemq.broker-url=tcp://192.168.10.130:61616

#配置 JMS 属性(消息目的地)
spring.jms.template.default-destination=custom-destination

(3)实现 消息监听(消息消费)

	@Autowired
    private JmsTemplate jmsTemplate;

    /**
     * 获取消息队列中(default-destination=custom-destination)的对象
     */
    @GetMapping("/user/poll")
    public Object pollUser(){
        return jmsTemplate.receiveAndConvert();
    }

一旦消息被消费了,则该条消息将会被 ActiveMQ 服务器删除!

(三)ActiveMQ Spring Cloud Stream Binder 实现

  创建 stream-binder-activemq 工程

1、添加依赖

		<!--
            Spring Boot 自动装配依赖
            假如你的Project A的某个依赖D添加了<optional>true</optional>,
            当别人通过pom依赖Project A的时候,D不会被传递依赖进来-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- 添加 activemq 依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-activemq</artifactId>
        </dependency>
        <!-- Spring Cloud Stream 核心库 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-stream</artifactId>
        </dependency>

2、实现 Binder 接口 - 实现消息发送/消费

/**
 * ActiveMQ MessageChannel Binder
 * @author 咸鱼
 * @date 2018/11/28 17:48
 */
public class ActiveMQMessageChannelBinder implements Binder<MessageChannel,
        ConsumerProperties, ProducerProperties>{

    @Autowired
    private JmsTemplate jmsTemplate;

    /**
     * 接收 ActiveMQ 消息
     * @param name
     * @param group
     * @param inboundBindTarget
     * @param consumerProperties
     * @return
     */
    @Override
    public Binding<MessageChannel> bindConsumer(String name, String group, MessageChannel inboundBindTarget, ConsumerProperties consumerProperties) {
        //todo:实现消息消费
        ConnectionFactory connectionFactory = jmsTemplate.getConnectionFactory();
        try {
            // 创造 JMS 链接
            Connection connection = connectionFactory.createConnection();
            // 启动连接
            connection.start();
            // 创建会话 Session
            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            // 创建消息目的
            Destination destination = session.createQueue(name);
            // 创建消息消费者
            MessageConsumer messageConsumer = session.createConsumer(destination);

            messageConsumer.setMessageListener(message -> {
                // message 来自于 ActiveMQ
                if (message instanceof ObjectMessage) {
                    ObjectMessage objectMessage = (ObjectMessage) message;
                    try {
                        Object object = objectMessage.getObject();
                        inputChannel.send(new GenericMessage<Object>(object));
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
            });
        } catch (JMSException e) {
            e.printStackTrace();
        }

        return () -> {
        };
    }

    /**
     * 负责发送消息到 ActiveMQ
     * @param name 配置文件中配置的 destination 名称
     * @param outboundBindTarget 消息管道
     * @param producerProperties
     * @return
     */
    @Override
    public Binding<MessageChannel> bindProducer(String name, MessageChannel outboundBindTarget, ProducerProperties producerProperties) {
        // MessageChannel 必须是 SubscribableChannel 类型
        Assert.isInstanceOf(SubscribableChannel.class, outboundBindTarget,
                "Binding is supported only for SubscribableChannel instances");

        //强转为 SubscribableChannel类型
        SubscribableChannel subscribableChannel = (SubscribableChannel)outboundBindTarget;


        subscribableChannel.subscribe(message -> {
            /*
             *     接收内部管道消息,来自于 MessageChannel#send(message),实际并没有发送消息,
             * 而是此消息将要发送到 ActiveMQ Broker。
             *     案例:
             *     我们在调用 UserServiceClientController#saveUserByActiveMQStreamBinder() 方法时,
             * 会通过 messageChannel.send(message) 向 ActiveMQ 发送消息,而这里先拦截到该消息,再由
             * 这里转发至 ActiveMQ
             */
            Object messageBody = message.getPayload();
            jmsTemplate.convertAndSend(name, messageBody);
        });
        return () -> System.out.println("Unbind");
    }
}

3、实现 Spring Cloud Stream Binder 自动装配

/**
 * ActiveMQ Stream Binder 自动装配
 * @author 咸鱼
 * @date 2018/11/28 18:08
 */
@Configuration
@ConditionalOnMissingBean(Binder.class)
public class ActiveMQStreamBinderAutoConfiguration {
    /**
     * 暴露自定义的 ActiveMQMessageChannelBinder Bean
     */
    @Bean
    public ActiveMQMessageChannelBinder activeMQMessageChannelBinder() {
        return new ActiveMQMessageChannelBinder();
    }
}

4、配置 META-INF/spring.binders

activemq:\
org.pc.activemq.ActiveMQStreamBinderAutoConfiguration

5、整合消息生产者 user-service-client 应用

(1)引入先前创建的 stream-binder-activemq 工程依赖

		<!--
            引入 stream-binder-activemq 项目依赖
            ${project.version}:该项目当前版本
             -->
        <dependency>
            <groupId>org.pc</groupId>
            <artifactId>stream-binder-activemq</artifactId>
            <version>${project.version}</version>
        </dependency>

(2)改造 UserMessage

/**
 * 用户消息 输出
 * @author 咸鱼
 * @date 2018/11/24 19:14
 */
public interface UserMessage {
    String OUTPUT = "output";

    @Output(OUTPUT)
    MessageChannel output();

    @Output("activemq-output")
    MessageChannel activeMQOut();
}

(3)配置 stream-binder-activemq 属性

# 消息管道 activemq-out 配置
#当项目中存在多个消息中间件:activemq、kafka,必须指定要绑定哪一个中间件
spring.cloud.stream.bindings.activemq-output.binder=activemq
spring.cloud.stream.bindings.activemq-output.destination=custom-destination

6、整合消息消费者 user-service-provider 应用

(1)引入先前创建的 stream-binder-activemq 工程依赖

		<!--
            引入 stream-binder-activemq 项目依赖
            ${project.version}:该项目当前版本
             -->
        <dependency>
            <groupId>org.pc</groupId>
            <artifactId>stream-binder-activemq</artifactId>
            <version>${project.version}</version>
        </dependency>

(2)改造 UserMessage

/**
 * {@link User} 消息 Stream 接口定义(PS:用于管道通信)
 * @author 咸鱼
 * @date 2018/11/24 15:56
 */
public interface UserMessage {

    String INPUT = "input";

    @Input(INPUT)
    SubscribableChannel input();

    @Input("activemq-in")
    SubscribableChannel activeMQIn();
}

(3)配置 stream-binder-activemq 属性

# 消息管道 activemq-in 配置
#当项目中存在多个消息中间件:activemq、kafka,必须指定要绑定哪一个中间件
spring.cloud.stream.bindings.activemq-in.binder=activemq
spring.cloud.stream.bindings.activemq-in.destination=custom-destination

(4)实现 User 消息监听

 @StreamListener("activemq-in")
    public void onUserMessage(User user) throws IOException {
        System.out.println("Subscribe by @StreamListener");
        userService.saveUser(user);
    }

    // 监听 ActiveMQ Stream
    userMessage.activeMQIn().subscribe(message -> {

        if (message instanceof GenericMessage) {
            GenericMessage genericMessage = (GenericMessage) message;
            User user = (User) genericMessage.getPayload();
            userService.saveUser(user);
        }
    });

猜你喜欢

转载自blog.csdn.net/panchang199266/article/details/84556188
今日推荐