RabbitMQ的几种方式的实现总结

来源:互联网 发布:网络做饭卖用啥软件 编辑:程序博客网 时间:2024/06/18 10:22


一, exchange direct


1,任何发送到Direct Exchange 的消息都会被转发到RouterKey中指定的Queue.
2,一般情况下可以使用rabbitMq自带的Exchange: " "  ,该Exchange的名字为空字符串,namely,default exchange.
3,这种模式下不需要将Exchange进行任何绑定操作.
4,消息传递的时候需要一个"RouterKey",可以简单的理解为要发送到的队列名字.
5,如果vhost中不存在RouterKey中指定的队列名字,则该消息会被抛弃.
任何发送到Direct Exchange的消息都会被转发到RouterKey中指定的Queue.






举个栗子:


1,首先是配置文件.RabbitMQConfig.java


i,创建ClassMapper;
ii,消息转换器,发送的时候;
iii,消息转换器,接收的时候;
iv,创建监听容器工厂;
v,创建Rabbit模板;




package com.yomob.api.config;


import java.util.HashMap;
import java.util.Map;
import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.ClassMapper;
import org.springframework.amqp.support.converter.DefaultClassMapper;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.yomob.api.entity.App;
import com.yomob.api.entity.Scene;
import com.yomob.api.entity.User;
import lombok.Data;


/**
 * @author Wengang Wang
 * @since Jun 11, 2017
 */
@EnableRabbit
@Configuration
@Data
public class RabbitMQConfig {


    @Bean(name = "classMapper")
    public ClassMapper createClassMapper(){
        DefaultClassMapper classMapper = new DefaultClassMapper();
        classMapper.setDefaultType(User.class);
        Map<String,Class<?>> map = new HashMap<String, Class<?>>();
        map.put("User",User.class);
        map.put("App",App.class);
        map.put("Scene", Scene.class);
        classMapper.setIdClassMapping(map);
        return classMapper;
    }


    @Bean(name = "userMessageConverter_send")
    public MessageConverter StudentMessageConverter_send(@Qualifier(value = "classMapper") ClassMapper classMapper) {
        Jackson2JsonMessageConverter messageConverter = new Jackson2JsonMessageConverter();
        messageConverter.setClassMapper(classMapper);
        return messageConverter;
    }




    @Bean(name = "userMessageConverter_receive")
    public MessageConverter StudentMessageConverter_receive() {
        DefaultClassMapper classMapper = new DefaultClassMapper();
        classMapper.setDefaultType(User.class);
        Map<String,Class<?>> map = new HashMap<String, Class<?>>();
        map.put("User",User.class);
        map.put("App",App.class);
        map.put("Scene",Scene.class);
        classMapper.setIdClassMapping(map);
        Jackson2JsonMessageConverter messageConverter = new Jackson2JsonMessageConverter();
        messageConverter.setClassMapper(classMapper);
        return messageConverter;
    }




    @Bean(name = "simpleRabbitListenerContainerFactory")
    SimpleRabbitListenerContainerFactory createSimpleRabbitListenerContainerFactory(
            @Qualifier(value = "userMessageConverter_receive") MessageConverter studentMessageConverter,
            ConnectionFactory connectionFactory) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        factory.setMessageConverter(studentMessageConverter);
        return factory;
    }




    @Bean(name = "rabbitTemplate")
    RabbitTemplate rabbitTemplate(
            @Qualifier(value = "userMessageConverter_send") MessageConverter studentMessageConverter,
            ConnectionFactory connectionFactory) {
        RabbitTemplate template = new RabbitTemplate(connectionFactory);
        template.setMessageConverter(studentMessageConverter);
        return template;
    }
}




2,生产者.


namely,我在controller类中进行了触发发送数据,充当生产者.
比如:
private final RabbitTemplate rabbitTemplate;
rabbitTemplate.convertAndSend("testDirectExchange","key1",toSave);




    @PostMapping("/signup")
    public ResponseEntity register(@RequestBody UserInfo request){
        User oldUser=userService.findByEmail(request.getEmail());
        if (!Objects.isNull(oldUser)){
            throw new ExistingValueException("Existing email");
        }
        User user=new UserHelper().convertUserInfoToUserEntity(request);
        user.setId(snowflake.nextHexString());
        String salt=passwordService.makeSalt();
        user.setSalt(salt);
        String credentials=passwordService.encryptPassword(user.getPassword(),salt);
        user.setCredentials(credentials);
        user.setAlg(passwordService.getAlgorithmName());
        user.setHashIterations(passwordService.getHashIterations());
        user.setLocked(Boolean.TRUE);
        user.setCreatedAt(new Date());
        user.setModifiedAt(new Date());
        User toSave=userService.saveUserWhenSignup(user);
        rabbitTemplate.convertAndSend("testDirectExchange","key1",toSave);
        return ResponseEntity.ok(new UserHelper().convertUserEntityToUserInfo(toSave));
    }




 3,消费者.
 
 A src/main/java/com/yomob/api/facility/Receiver.java




这里面配置了监听,对生产者的动作进行了监听,并且配置了队列,交换机以及containerFactory
@RabbitListener(
        containerFactory = "simpleRabbitListenerContainerFactory",
        bindings = @QueueBinding(
                value = @Queue(value = "testDirectQueue1",durable = "true"),
                exchange = @Exchange(value = "testDirectExchange",type = ExchangeTypes.DIRECT),
                key = "key1")
)   


package com.yomob.api.facility;


import java.util.Date;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import com.yomob.api.entity.User;




/**
 * @author Wengang Wang
 * @since Jun 11, 2017
 */
@RabbitListener(
        containerFactory = "simpleRabbitListenerContainerFactory",
        bindings = @QueueBinding(
                value = @Queue(value = "testDirectQueue1",durable = "true"),
                exchange = @Exchange(value = "testDirectExchange",type = ExchangeTypes.DIRECT),
                key = "key1")
)
@Component
public class Receiver {
    @RabbitHandler
    public void receiveMessage(User user) {
        System.out.println("Received <" + user.getId()+ ">");
    }




    @RabbitHandler
    public void receiveMessage(String id) {
        System.out.println("Received <" + id + ">");
    }


    @RabbitHandler
    public void receiveMessage(Date createdAt) {
        System.out.println("Received <" + createdAt + ">");
    }
}


补充几点,
1,因为笔者的生产者都是在controller层中的,在上面有有提到.就不在这里赘述了.
2,生产者消费者模式这块主要有三大块要点,配置文件,消费者,和生产者.外加些实体类的注解等.笔者觉得最核心的是配置文件了,因为这块牵涉到
构建ClassMapper,消息转换器,监听容器工厂和Rabbit模板等.
3,在实体类头再打上这些注解
@Data
@ToString
@NoArgsConstructor






二,exchange fanout




i,任何发送到该交换机的消息到会被转发到与该交换机绑定的所以Queue上.
ii,这种模式不需要RouterKey.
iii,这种模式需要提前将Exchange 与Queue进行绑定,一个Exchange可以绑定多个Queue,一个Queue也可以绑定多个Exchange.
iv,可以理解为路由表的模式.
如果接受的消息的Exchange没有与任何Queue绑定,则消息会被抛弃.
一个交换机绑定 2个队列.
rabbitTemplate.convertAndSend("testFanoutExchange",null, abc + " from RabbitMQ!");
如上所以,只是需要在 @rabbitlistener 中绑定好 exchange,那么testFanoutQueue1,testFanoutQueue2 队列都会得到消息。




三, exchange topic 




1.这种模式较为复杂,简单来说,就是每个队列都有其关心的主题,所有的消息都带有一个“标题”(RouteKey),Exchange会将消息转发到所有关注主题能与RouteKey模糊匹配的队列。
2.这种模式需要RouteKey,也许要提前绑定Exchange与Queue。
3.在进行绑定时,要提供一个该队列关心的主题,如“#.log.#”表示该队列关心所有涉及log的消息(一个RouteKey为”MQ.log.error”的消息会被转发到该队列)。
4.“#”表示0个或若干个关键字,“”表示一个关键字。如“log.”能与“log.warn”匹配,无法与“log.warn.timeout”匹配;但是“log.#”能与上述两者匹配。
5.同样,如果Exchange没有发现能够与RouteKey匹配的Queue,则会抛弃此消息。




tip:
一般的字符串在传输的时候直接操作是可以的,但是要是需要操作实体对象的时候,务必注意转换.换言之,对象的转换.笔者的操作就是属于对象的.
所以会在文首提到 RabbitMQConfig.java 这个里面给出了详细的转换配置.


原创粉丝点击