springboot整合RabbitMQ
- 安裝rabbitmq
- 進(jìn)入cmd進(jìn)入D:\RabbitMQ Server\rabbitmq_server-3.6.10\sbin
- 執(zhí)行rabbitmq-plugins enable rabbitmq_management
- 打開瀏覽器并訪問:http://localhost:15672/
- 默認(rèn)賬戶密碼都為guest
創(chuàng)建項目
依賴
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
配置文件
spring.application.name=rabbitmq-demo
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=123456
消息生產(chǎn)者
@Component
public class Sender {
@Autowired
private AmqpTemplate rabbitTemplate;
public void send() {
String context = "hello " + new Date();
System.out.println("Sender : " + context);
this.rabbitTemplate.convertAndSend("hello", context);
}
}
消息消費者
@Component
@RabbitListener(queues = "hello")
public class Receiver {
@RabbitHandler
public void process(String hello) {
System.out.println("Receiver : " + hello);
}
}
rabbit配置
@Configuration
public class RabbitConfig {
@Bean
public Queue helloQueue() {
return new Queue("hello");
}
}
Application
@SpringBootApplication
public class HelloApplication {
public static void main(String[] args) {
SpringApplication.run(HelloApplication.class, args);
}
}
測試類
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class ApplicationTest {
@Autowired
private Sender sender;
@Test
public void hello() throws Exception {
sender.send();
}
}
springcloud整合RabbitMQ使用消息總線更新配置文件
添加依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
配置文件添加
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=123456
發(fā)送post請求到localhost:2001/bus/refresh便可以刷新所有服務(wù)的配置
原理分析
我們通過使用Spring Cloud Bus與Spring Cloud Config的整合,并以RabbitMQ作為消息代理,實現(xiàn)了應(yīng)用配置的動態(tài)更新。

整個方案的架構(gòu)如上圖所示,其中包含了Git倉庫、Config Server、以及微服務(wù)“Service A”的三個實例,這三個實例中都引入了Spring Cloud Bus,所以他們都連接到了RabbitMQ的消息總線上。
當(dāng)我們將系統(tǒng)啟動起來之后,“Service A”的三個實例會請求Config Server以獲取配置信息,Config Server根據(jù)應(yīng)用配置的規(guī)則從Git倉庫中獲取配置信息并返回。
此時,若我們需要修改“Service A”的屬性。首先,通過Git管理工具去倉庫中修改對應(yīng)的屬性值,但是這個修改并不會觸發(fā)“Service A”實例的屬性更新。我們向“Service A”的實例3發(fā)送POST請求,訪問/bus/refresh接口。此時,“Service A”的實例3就會將刷新請求發(fā)送到消息總線中,該消息事件會被“Service A”的實例1和實例2從總線中獲取到,并重新從Config Server中獲取他們的配置信息,從而實現(xiàn)配置信息的動態(tài)更新。
而從Git倉庫中配置的修改到發(fā)起/bus/refresh的POST請求這一步可以通過Git倉庫的Web Hook來自動觸發(fā)。由于所有連接到消息總線上的應(yīng)用都會接受到更新請求,所以在Web Hook中就不需要維護所有節(jié)點內(nèi)容來進(jìn)行更新,從而解決了通過Web Hook來逐個進(jìn)行刷新的問題。
指定刷新范圍
上面的例子中,我們通過向服務(wù)實例請求Spring Cloud Bus的/bus/refresh接口,從而觸發(fā)總線上其他服務(wù)實例的/refresh。但是有些特殊場景下(比如:灰度發(fā)布),我們希望可以刷新微服務(wù)中某個具體實例的配置。
Spring Cloud Bus對這種場景也有很好的支持:/bus/refresh接口還提供了destination參數(shù),用來定位具體要刷新的應(yīng)用程序。比如,我們可以請求/bus/refresh?destination=customers:9000,此時總線上的各應(yīng)用實例會根據(jù)destination屬性的值來判斷是否為自己的實例名,若符合才進(jìn)行配置刷新,若不符合就忽略該消息。
destination參數(shù)除了可以定位具體的實例之外,還可以用來定位具體的服務(wù)。定位服務(wù)的原理是通過使用Spring的PathMatecher(路徑匹配)來實現(xiàn),比如:/bus/refresh?destination=customers:**,該請求會觸發(fā)customers服務(wù)的所有實例進(jìn)行刷新。
架構(gòu)優(yōu)化
既然Spring Cloud Bus的/bus/refresh接口提供了針對服務(wù)和實例進(jìn)行配置更新的參數(shù),那么我們的架構(gòu)也相應(yīng)的可以做出一些調(diào)整。在之前的架構(gòu)中,服務(wù)的配置更新需要通過向具體服務(wù)中的某個實例發(fā)送請求,再觸發(fā)對整個服務(wù)集群的配置更新。雖然能實現(xiàn)功能,但是這樣的結(jié)果是,我們指定的應(yīng)用實例就會不同于集群中的其他應(yīng)用實例,這樣會增加集群內(nèi)部的復(fù)雜度,不利于將來的運維工作,比如:我們需要對服務(wù)實例進(jìn)行遷移,那么我們不得不修改Web Hook中的配置等。所以我們要盡可能的讓服務(wù)集群中的各個節(jié)點是對等的。
因此,我們將之前的架構(gòu)做了一些調(diào)整,如下圖所示:
我們主要做了這些改動:
- 在Config Server中也引入Spring Cloud Bus,將配置服務(wù)端也加入到消息總線中來。
- /bus/refresh請求不在發(fā)送到具體服務(wù)實例上,而是發(fā)送給Config Server,并通過destination參數(shù)來指定需要更新配置的服務(wù)或?qū)嵗?/li>
通過上面的改動,我們的服務(wù)實例就不需要再承擔(dān)觸發(fā)配置更新的職責(zé)。同時,對于Git的觸發(fā)等配置都只需要針對Config Server即可,從而簡化了集群上的一些維護工作。