前言
最近开发中遇到很多相同的问题,下意识去翻自己的历史记录,但又没能快速定位。我的trilium一直用来记录自己的周报和相关教程,对于常见的bug和修复方案也找不到合适的地方,只能穿插在日报的历史中,随时间沉没。无意间翻到子舒的奇趣周刊,Bug周刊也由此而生。
Boot项目连接多个MQ
问题描述
最近公司因为业务需求,需要系统A向系统B推送对应的补充字段,原系统A在nacos中配置了对应的MQ,并在系统运行时自动初始化。config包中并没有对应的 FactoryBean 。
1 2 3 4 5 6 7 8
| spring: rabbitmq: host: 127.0.0.1 port: 5672 username: guest virtual-host: / password: guest
|
解决方案
1️⃣ nacos中配置MQ信息
在对应模块中添加对应的MQ信息,不同的MQ配置对应不同的系统。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
rabbitmqB: host: 127.0.0.2 port: 5672 username: guest virtual-host: / password: guest
rabbitmqDefault: host: 127.0.0.1 port: 5672 username: guest virtual-host: / password: guest
|
2️⃣ 在系统A Business模块中添加对应的FactoryBean
因为系统A的Business模块中需要连接两个MQ,所以需要添加两个FactoryBean。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| @Configuration public class RabbitMQConfig {
@Value("${rabbitmqDefault.port}") private int port;
@Value("${rabbitmqDefault.host}") private String host;
@Value("${rabbitmqDefault.username}") private String username;
@Value("${rabbitmqDefault.password}") private String password; @Value("${rabbitmqDefault.virtual-host}") private String virtualHost;
@Primary @Bean(name = "defaultConnectionFactory") public ConnectionFactory defaultConnectionFactory() { CachingConnectionFactory factory = new CachingConnectionFactory(host, port); factory.setUsername(username); factory.setPassword(password); factory.setVirtualHost(virtualHost); factory.setPublisherConfirms(true); factory.setPublisherReturns(true); return factory; }
@Primary @Bean(name = "defaultRabbitTemplate") public RabbitTemplate defaultRabbitTemplate(@Qualifier("defaultConnectionFactory") ConnectionFactory defaultConnectionFactory) { return new RabbitTemplate(defaultConnectionFactory); }
@Primary @Bean(name = "defaultListenerContainerFactory") public SimpleRabbitListenerContainerFactory defaultListenerContainerFactory(@Qualifier("defaultConnectionFactory") ConnectionFactory defaultConnectionFactory) { SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory(); factory.setConnectionFactory(defaultConnectionFactory); factory.setAcknowledgeMode(AcknowledgeMode.MANUAL); return factory; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| @Configuration public class RabbitMQBConfig {
@Value("${rabbitmqB.port}") private int port;
@Value("${rabbitmqB.host}") private String host;
@Value("${rabbitmqB.username}") private String username;
@Value("${rabbitmqB.password}") private String password;
@Value("${rabbitmqB.virtual-host}") private String virtualHost;
@Bean(name = "BConnectionFactory") public ConnectionFactory BConnectionFactory() { CachingConnectionFactory factory = new CachingConnectionFactory(host, port); factory.setUsername(username); factory.setPassword(password); factory.setVirtualHost(virtualHost); factory.setPublisherConfirms(true); factory.setPublisherReturns(true); return factory; }
@Bean(name = "BRabbitTemplate") public RabbitTemplate BRabbitTemplate(@Qualifier("BConnectionFactory")ConnectionFactory BConnectionFactory) { return new RabbitTemplate(BConnectionFactory); }
@Bean(name = "BListenerContainerFactory") public SimpleRabbitListenerContainerFactory BListenerContainerFactory(@Qualifier("BConnectionFactory")ConnectionFactory BConnectionFactory) { SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory(); factory.setConnectionFactory(BConnectionFactory); factory.setAcknowledgeMode(AcknowledgeMode.MANUAL); return factory; } }
|
3️⃣ 声明原系统A的生产者(defaultRabbitTemplate)
1 2 3
| @Autowired @Qualifier("defaultRabbitTemplate") private RabbitTemplate rabbitTemplate;
|
4️⃣ 修改原系统A的消费者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Configuration @Component @Slf4j public class RabbitMqListenerConfig {
@RabbitListener(queuesToDeclare = @Queue(RabbitLogConstant.TEST_QUEUE), containerFactory = "defaultListenerContainerFactory") public void process(BusinessLog businessLog, Message message, Channel channel) throws IOException { log.info("{}队列收到消息:{}", RabbitLogConstant.TEST_QUEUE, JSONUtil.toJsonStr(businessLog)); try { } catch (Exception e) { log.error("{}队列消息处理异常,{}", RabbitLogConstant.TEST_QUEUE, e.getMessage()); } channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); } }
|
5️⃣ 在系统A Bussiness模块实现类中声明推送至系统B的生产者
1 2 3 4 5
| @Autowired @Qualifier("BRabbitTemplate") private RabbitTemplate rabbitTemplateB;
rabbitTemplateB.convertAndSend(RabbitLogConstant.BUSINESS_QUEUE, JSONUtil.toJsonStr(businessData));
|
不能仅在系统A的Business模块中声明新的FactoryBean,不声明原默认的FactoryBean,否则新的MQ配置会覆盖系统A的默认MQ配置。
也就是说,原系统A的Business模块在此情况下,所有的生产都会推送到系统B,消费者也监听不到原MQ。B系统又没有对应的消费者,就会导致消息堆积。
Pageable分页size上限
问题描述
在开发信息台账时,导出需要全部的数据,在最初设计接口时,使用Pageable分页,打算导出时直接设置size为极值。
但实际测试发现接口只返回了2000条数据,查看Pageable的源码发现,默认的size上限为2000。
解决方案
在当前模块 config 包中添加对应的配置,重写Pageable的size上限。运行boot时,会自动加载。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| package com.test.services.currentpackage.config;
import org.springframework.context.annotation.Configuration; import org.springframework.data.web.PageableHandlerMethodArgumentResolver; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration public class PageConfig extends WebMvcConfigurerAdapter {
private static final int PMP_MAX_PAGE_SIZE = 100000;
@Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { PageableHandlerMethodArgumentResolver resolver = new PageableHandlerMethodArgumentResolver();
resolver.setMaxPageSize(PMP_MAX_PAGE_SIZE); argumentResolvers.add(resolver); super.addArgumentResolvers(argumentResolvers); } }
|
结构体收发读取失败
问题描述
接上面MQ的解决方案,A、B系统接口联调时,A系统发送数据,B系统接收数据。但B系统从MQ中读取数据为空,使用的是相同的 Dto。
解决方案
经确认数据无误,于是怀疑是Dto的属性问题,@Data、@Getter、@Setter注解均已添加,但仍未解决。最终添加反序列化操作成功。
1 2
| rabbitTemplateB.setMessageConverter(new Jackson2JsonMessageConverter()); rabbitTemplateB.convertAndSend(RabbitMQConfig.TOPIC_EXCHANGE_DATA_PUSH_B, key, dataPushBDto);
|