序
我們知道不同中間件之間存在很多差異,如RocketMQ支持定時重試,每次重試間隔逐漸增加。
Kafka,RabbitMq不支持重試。我們要做一個統一的Spring Cloud Starter
實現效果:
(1)讓Kafka,RabbitMq支持消息重試。
(2)使用不同的消息中間件時,我們不需要在maven引入不同的Jar包。
開發好後的使用效果
對於不同的中間件,我們僅需在application.yaml中改一下配置信息
// 如果想使用 rocketMq
paas:
mq:
rocket:
target: 106.14.13.60
// 如果想使用 rabbitMq
paas:
mq:
kafka:
target: 106.14.13.60
發送消息(ProducerServer爲我們自己的生產者)
@Autowired
private ProducerServer producerServer;
...
producerServer.send("發送的信息");
消費消息
@Component
public class OnsMessageListener implements MessageListener {
@Override
public String getTopic() {
return "TOPIC";
}
@Override
public String getTag() {
return "TAG";
}
@Override
public void process(ConsumeMessage message) {
System.out.println("Listener正在監聽:"+message.getValueAsString());
// 如果拋出異常,會進行重試一共重試16次:10s、30s、1min、2min …… 10min、20min、30min、1h、2h,最後放入死信隊列
}
}
我們要考慮很多步驟要做
- 適配不同消息隊列重試機制,如何讓Kafka,RabbitMq支持重試?如延時消息配合死信隊列,定時任務…
- 適配不同消息隊列基本組件,如kafka有topic,但是無tag…
- 適配不同消息隊列的消費類型集羣消費,廣播消費…
如果想實現這個效果,需要深入的瞭解這些中間件。這一章首先搭建一個項目框架。
有以下步驟
- 引入對應的依賴
- 編寫實現類
- 編寫配置文件讀取類 主要註解是@ConfigruationProperties
- 編寫自動裝配類
- 在resources/META-INF/spring.factories 中配置我們的自動裝配類
- maven install後引入依賴即可使用
實戰
首先看下項目結構
mq-starter爲我們要開發的sdk
demo爲引入mq-starter後的測試項目
開始開發吧~
- 引入的依賴
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
</dependencies>
說明:
第一個依賴 主要是爲編譯器配置的 可以根據properties 鼠標右鍵 點到用這個屬性的類上個
第二個依賴 主要是爲了自動裝配
- 編寫自己的功能實現類,此處爲實現producerServer.send()方法
由於無論KafkaProducerServer還是RocketProducerServer,都是生產者,因此我們抽出一個接口
public interface ProducerServer {
/**
* 發送消息
*
* @param msg 消息內容
* @return 消息Id
*/
String send(String msg);
}
定義兩個實現類
public class KafkaProducerServer implements ProducerServer {
String target;
public KafkaProducerServer(String target) {
this.target = target;
}
@Override
public String send(String msg) {
System.out.println("kafka ip:" + target + " msg:" + msg);
return null;
}
}
public class RocketProducerServer implements ProducerServer {
String target;
public RocketProducerServer(String target) {
this.target = target;
}
@Override
public String send(String msg) {
System.out.println("rocket ip:" + target + " msg:" + msg);
return null;
}
}
- 編寫配置文件讀取類
demo項目中application.yaml中定義了消息隊列的配置(target ),我們要拿到demo中的配置信息,纔可以進行發送
@ConfigurationProperties(prefix = "paas.mq.kafka")
@Data
public class KafkaAutoConfigruationProperties {
private String target;
}
@ConfigurationProperties(prefix = "paas.mq.rocket")
@Data
public class RocketAutoConfigruationProperties {
private String target;
}
這裏我們要讀取的配置就是paas.mq.kafka.targer/paas.mq.rocket.targer的值
@ConfigurationProperties註解的作用就是讀取配置文件指定屬性的值
- 編寫自動裝配類
@Configuration
@EnableConfigurationProperties(KafkaAutoConfigruationProperties.class)
@ConditionalOnClass(KafkaProducerServer.class)
public class KafkaAutoConfigrution {
@Autowired
private KafkaAutoConfigruationProperties kafkaAutoConfigruationProperties;
@ConditionalOnProperty("paas.mq.kafka.target")
@Bean
public KafkaProducerServer kafkaProducerServer() {
return new KafkaProducerServer(kafkaAutoConfigruationProperties.getTarget());
}
}
@Configuration
@EnableConfigurationProperties(RocketAutoConfigruationProperties.class)
@ConditionalOnClass(RocketProducerServer.class)
public class RocketAutoConfigrution {
@Autowired
private RocketAutoConfigruationProperties rocketAutoConfigruationProperties;
@ConditionalOnProperty("paas.mq.rocket.target")
@Bean
public RocketProducerServer rocketProducerServer() {
return new RocketProducerServer(rocketAutoConfigruationProperties.getTarget());
}
}
4.1.@Configuration
標識本類是配置類(相當於spring中application.xml)
4.2.@EnableConfigurationProperties(AutoConfigruationProperties.class)
如果AutoConfigruationProperties中有註解@ConfigurationProperties 那麼這個類就
會被加到spring上下文的容器中,也就是可以通過@Autowire來注入
4.3.@ConditionalOnClass
當類路徑下有指定類的情況下 才進行下一步
4.4.@ConditionalOnMissingBean
當spring容器中沒有這個Bean的時候才進行下一步
4.5.@ConditionalOnProperty(“paas.mq.rocket.target”)
當配置文件存在“paas.mq.rocket.target”才進行下一步
我們僅需一個bean,無需同時存在RocketProducerServer,KafkaProducerServer。因此拋棄@ConditionalOnMissingBean,而使用@ConditionalOnProperty(“paas.mq.rocket.target”),選擇性的產生一個Bean對象。
- 在resources/META-INF下添加spring.factories 指定自動裝配的類也叫入口 內容如下:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.wpp.paas.foundation.autoconfigure.mq.kafka.KafkaAutoConfigrution,\
com.wpp.paas.foundation.autoconfigure.mq.rocket.RocketAutoConfigrution
- 現在在demo項目中直接自動注入我們的bean就ok了