Before integration, rabbitMqJAR package should be introduced in springboot. The version number can be customized for you. This project follows the version of springboot
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency>
Then start to build configuration items, and add rabbitMQ configuration in application.properties of springboot project
# rabbitMQ configuration item # rabbitmq access domain name spring.rabbitmq.host=127.0.0.1 # rabbitmq port number spring.rabbitmq.port=5672 # rabbitMq account spring.rabbitmq.username= # rabbitMq password spring.rabbitmq.password= # Turn on confirm callback p - > exchange spring.rabbitmq.publisher-confirms=true #Enable returnedMessage callback exchange - > queue spring.rabbitmq.publisher-returns=true #Set ack queue - > C spring.rabbitmq.listener.simple.acknowledge-mode=manual spring.rabbitmq.listener.simple.prefetch=100 spring.rabbitmq.template.mandatory=true #Open consumer retry spring.rabbitmq.listener.simple.retry.enabled=true #Maximum number of retries (if 5 retries are not enough, the message will be deleted. By default, there is no limit to the number of retries. It is recommended to control the number of retries within 10) spring.rabbitmq.listener.simple.retry.max-attempts=5 #Retry interval spring.rabbitmq.listener.simple.retry.initial-interval=3000 spring.rabbitmq.virtual-host=/
Then build rabbitMQ configuration RabbitMQConfig
@Configuration public class RabbitMQConfig { private Logger logger = LoggerFactory.getLogger(RabbitMQConfig.class); @Autowired private CachingConnectionFactory connectionFactory; /** * Accept data automatically converted to Json */ @Bean("messageConverter") public MessageConverter messageConverter() { return new Jackson2JsonMessageConverter(); } @Bean("rabbitTemplate") public RabbitTemplate rabbitTemplate() { final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory); rabbitTemplate.setMessageConverter(messageConverter()); connectionFactory.setPublisherConfirms(true); connectionFactory.setPublisherReturns(true); rabbitTemplate.setMandatory(true); rabbitTemplate.setMessageConverter(messageConverter()); rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() { @Override public void confirm(CorrelationData correlationData, boolean ack, String cause) { if(!ack) { logger.info("Message sending failed:correlationData({}),ack({}),cause({})", correlationData, ack, cause); } } }); rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() { @Override public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) { logger.info("Message lost:exchange({}),route({}),replyCode({}),replyText({}),message:{}", exchange, routingKey, replyCode, replyText, message); } }); return rabbitTemplate; } @Bean("rabbitAdmin") public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) { RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory); System.err.println("RabbitAdmin Started..."); // Set to load this class automatically when starting the spring container (this parameter is now true by default, which can be ignored) rabbitAdmin.setAutoStartup(true); return rabbitAdmin; } }
Then define the initialization listener method MQListenerConfig
@Configuration public class MQListenerConfig { @Bean public MessageListenerConfig messageListenerConfig(RabbitAdmin admin, CachingConnectionFactory rabbitConnectionFactory) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException { MessageListenerConfig messageListenerConfig = new MessageListenerConfig(); messageListenerConfig.init(admin, rabbitConnectionFactory); return messageListenerConfig; } }
Initializing the listening method to obtain the queue and listener of consumers in the form of annotation
@Component public class MessageListenerConfig { public void init(RabbitAdmin admin, CachingConnectionFactory rabbitConnectionFactory) throws ClassNotFoundException, IOException, InstantiationException, IllegalAccessException { Map<String, AbstractConsumer> map = SpringUtil.getBeansOfType(AbstractConsumer.class);//Query subclass under AbstractConsumer parent List<AbstractConsumer> abstractConsumerList = new ArrayList<AbstractConsumer>(map.values());//Convert the above subclass to List collection SendMQService sendMQService = SpringUtil.getBean(RabbitServiceImpl.class);//Get rabbitMqService interface this.init(abstractConsumerList, 0, admin, rabbitConnectionFactory,sendMQService);//Initialization parameters } private void init(List<AbstractConsumer> clazzList, int index, RabbitAdmin admin, CachingConnectionFactory rabbitConnectionFactory,SendMQService sendMQService) { if (EmptyUtils.isEmpty(clazzList) || clazzList.size() <= index) { return; } AbstractConsumer abstractConsumer = clazzList.get(index); RabbitMq rabbitMq = abstractConsumer.getClass().getAnnotation(RabbitMq.class);// Obtain rabbitMQ annotation information according to reflection if (rabbitMq == null) { this.init(clazzList, index + 1, admin, rabbitConnectionFactory,sendMQService); } String queueString = rabbitMq.queues(); // queue String routingKeyString = rabbitMq.routingKey(); // exchanger String exchangeString = rabbitMq.exchange(); // Routing rules int count = rabbitMq.consumersPerQueue(); // Number of consumers per queue DirectMessageListenerContainer container = new DirectMessageListenerContainer(rabbitConnectionFactory); Queue queue = new Queue(queueString);// Declaration queue admin.declareQueue(queue);// Initialize queue if (EmptyUtils.isNotEmpty(exchangeString) && EmptyUtils.isNotEmpty(routingKeyString)) { AbstractMQService mqService = (AbstractMQService) SpringUtil.getBean(rabbitMq.exchangeTypes() + AbstractMQService.SERVICE_NAME); AbstractExchange exchange = mqService.initExchange(exchangeString); admin.declareExchange(exchange); Binding binding = mqService.initBinding(queue, exchange, routingKeyString);// Initialize data from different queues admin.declareBinding(binding); } MessageListenerAdapter adapter = new MessageListenerAdapter(abstractConsumer); adapter.setEncoding("utf-8"); container.setConsumersPerQueue(rabbitMq.consumersPerQueue()); container.setQueues(queue);// Listener configuration queue container.setMessageListener(adapter); container.setAutoDeclare(true); container.setAcknowledgeMode(rabbitMq.mode()); container.setConsumersPerQueue(count); // Start the corresponding adapter container.start(); sendMQService.addContainer(queueString, container); this.init(clazzList, index + 1, admin, rabbitConnectionFactory,sendMQService); } }
Initial switch and binding relationship interface
public interface AbstractMQService { static final String SERVICE_NAME = "MQService"; /** * Initialize switch * @return */ public AbstractExchange initExchange(String exchangeName); /** * Initialize binding relationship * @param routeKey * @return */ public Binding initBinding(Queue queue,AbstractExchange exchange,String routeKey); }
The initial switch and binding relationship implementation classes are DirectMQServiceImpl, FanoutMQServiceImpl and TopicMQServiceImpl, respectively
@Service("directMQService") public class DirectMQServiceImpl implements AbstractMQService { @Override public AbstractExchange initExchange(String exChangeName) { DirectExchange exchange = new DirectExchange(exChangeName); return exchange; } @Override public Binding initBinding(Queue queue, AbstractExchange exChange, String routeKey) { DirectExchange exchange = (DirectExchange) exChange; DestinationConfigurer bindConfigurer = BindingBuilder.bind(queue); DirectExchangeRoutingKeyConfigurer routKeyConfigurer = bindConfigurer.to(exchange); return routKeyConfigurer.with(routeKey); } }
@Service("fanoutMQService") public class FanoutMQServiceImpl implements AbstractMQService { @Override public AbstractExchange initExchange(String exChangeName) { FanoutExchange exchange = new FanoutExchange(exChangeName); return exchange; } @Override public Binding initBinding(Queue queue, AbstractExchange exChange, String routeKey) { FanoutExchange exchange = (FanoutExchange) exChange; DestinationConfigurer bindConfigurer = BindingBuilder.bind(queue); Binding binding = bindConfigurer.to(exchange); return binding; } }
@Service("topicMQService") public class TopicMQServiceImpl implements AbstractMQService { @Override public AbstractExchange initExchange(String exChangeName) { TopicExchange exchange = new TopicExchange(exChangeName); return exchange; } @Override public Binding initBinding(Queue queue, AbstractExchange exChange, String routeKey) { TopicExchange exchange = (TopicExchange) exChange; DestinationConfigurer bindConfigurer = BindingBuilder.bind(queue); TopicExchangeRoutingKeyConfigurer routKeyConfigurer = bindConfigurer.to(exchange); return routKeyConfigurer.with(routeKey); } }
Custom annotation
@Target(value = { ElementType.FIELD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) public @interface RabbitMq { /** * queue * * @return */ public String queues() default ""; /** * exchanger * * @return */ public String exchange() default ""; /** * Routing rules * * @return */ public String routingKey() default ""; /** * Persistence or not * * @return */ public boolean isPersistence() default true; /** * Confirmation mode * * @return */ public AcknowledgeMode mode() default AcknowledgeMode.MANUAL; /** * Number of consumers per queue * * @return */ public int consumersPerQueue() default 1; /** * Exchange type * * @return */ public String exchangeTypes() default ExchangeTypes.DIRECT; }
User defined consumer AbstractConsumer, which is used for general purpose. Each additional consumer only needs to inherit and then process the business logic
public abstract class AbstractConsumer extends MessagingMessageListenerAdapter { protected static final String MQ_CORRELATIONDATA_KEY = "spring_returned_message_correlation"; public static final String MQ_CACHE_MQ_KEY = "rabbitMQ.queues:"; public static final Integer FAIL_MAX_COUNT = 5; private RedisService redisService = SpringUtil.getBean(RedisService.class); @Override public void onMessage(Message message, Channel channel) throws IOException { MessageProperties messageProperties = message.getMessageProperties(); long deliveryTag = messageProperties.getDeliveryTag(); String correlationId = (String) message.getMessageProperties().getHeaders().get(MQ_CORRELATIONDATA_KEY); String queues = messageProperties.getConsumerQueue(); String cacheKey = new StringBuilder().append(MQ_CACHE_MQ_KEY).append(queues).append(":").append(correlationId).toString(); Integer failCount = (Integer)redisService.get(cacheKey); try { this.handleMessage(new String(message.getBody(), "UTF-8")); channel.basicAck(deliveryTag, false); redisService.del(new StringBuilder().append(correlationId).toString()); } catch (Exception e) { if(failCount > FAIL_MAX_COUNT) { return; } redisService.incr(cacheKey, 1, new Long(CacheTime.CACHE_EXP_THIRTY_SECONDS)); channel.basicNack(deliveryTag, false, false); } } public abstract void handleMessage(String message); }
What's not perfect? Please give me more advice! For the first time