Spring Boot 整合 RocketMQ 的全流程(消息發(fā)送、消費(fèi)、重試)
RocketMQ 作為阿里開源的分布式消息中間件,憑借高吞吐量、低延遲、高可靠性等特性,被廣泛應(yīng)用于分布式系統(tǒng)的異步通信、解耦、削峰填谷等場(chǎng)景。Spring Boot 作為主流的微服務(wù)開發(fā)框架,其自動(dòng)配置機(jī)制能極大簡(jiǎn)化與第三方組件的整合過程。本文將從實(shí)戰(zhàn)角度出發(fā),詳細(xì)講解 Spring Boot 如何整合 RocketMQ,覆蓋普通消息發(fā)送、消息消費(fèi)、消息重試等核心流程,并提供完整的代碼示例。
一、環(huán)境準(zhǔn)備
1. 基礎(chǔ)環(huán)境依賴
- JDK 8 及以上(RocketMQ 對(duì) JDK 版本有一定要求,推薦 8/11)
- Maven 3.6+(項(xiàng)目構(gòu)建工具)
- RocketMQ 4.9.7(本文使用的穩(wěn)定版本,可根據(jù)需求選擇最新版本)
- Spring Boot 2.7.15(與 RocketMQ Starter 適配的版本)
2. RocketMQ 服務(wù)部署
首先需要搭建 RocketMQ 服務(wù)環(huán)境,可選擇本地單機(jī)部署或集群部署,本文以本地單機(jī)為例:
- 從 RocketMQ 官網(wǎng) 下載對(duì)應(yīng)版本的安裝包,解壓到本地目錄。
- 啟動(dòng) NameServer:
# 進(jìn)入 RocketMQ 解壓目錄的 bin 文件夾 cd rocketmq-all-4.9.7-bin-release/bin # 啟動(dòng) NameServer(Windows 系統(tǒng)執(zhí)行 mqnamesrv.cmd) nohup sh mqnamesrv &
- 啟動(dòng) Broker:
# 啟動(dòng) Broker(Windows 系統(tǒng)執(zhí)行 mqbroker.cmd) nohup sh mqbroker -n localhost:9876 autoCreateTopicEnable=true &
注:
autoCreateTopicEnable=true表示自動(dòng)創(chuàng)建主題,方便測(cè)試,生產(chǎn)環(huán)境建議提前手動(dòng)創(chuàng)建主題。
二、項(xiàng)目初始化與依賴配置
1. 創(chuàng)建 Spring Boot 項(xiàng)目
通過 Spring Initializr(https://start.spring.io/)創(chuàng)建一個(gè) Spring Boot 項(xiàng)目,選擇基礎(chǔ)依賴(如 Spring Web),也可手動(dòng)創(chuàng)建 Maven 項(xiàng)目并配置 pom.xml。
2. 引入 RocketMQ 依賴
在 pom.xml 中添加 RocketMQ Spring Boot Starter 依賴,注意版本適配(本文使用 2.2.3 版本,與 RocketMQ 4.9.7 適配):
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.15</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>spring-boot-rocketmq-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-rocketmq-demo</name>
<description>Spring Boot RocketMQ 整合示例</description>
<properties>
<java.version>1.8</java.version>
<rocketmq-spring-boot-starter.version>2.2.3</rocketmq-spring-boot-starter.version>
</properties>
<dependencies>
<!-- Spring Web 依賴,用于提供接口測(cè)試 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- RocketMQ Spring Boot Starter -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>${rocketmq-spring-boot-starter.version}</version>
</dependency>
<!-- 測(cè)試依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>3. 配置 RocketMQ 連接信息
在 application.yml(或 application.properties)中配置 RocketMQ 的 NameServer 地址、生產(chǎn)者組等信息:
spring:
application:
name: spring-boot-rocketmq-demo
# RocketMQ 配置
rocketmq:
# NameServer 地址,多個(gè)地址用分號(hào)分隔
name-server: localhost:9876
# 生產(chǎn)者配置
producer:
# 生產(chǎn)者組名,必須唯一
group: demo-producer-group
# 發(fā)送消息的超時(shí)時(shí)間,默認(rèn) 3000ms
send-message-timeout: 3000
# 消息體最大長(zhǎng)度,默認(rèn) 4MB
max-message-size: 4194304
# 壓縮消息的閾值,默認(rèn) 4KB
compress-message-body-threshold: 4096
# 重試次數(shù),默認(rèn) 2 次
retry-times-when-send-failed: 2
# 異步發(fā)送失敗時(shí)是否重試其他 Broker,默認(rèn) false
retry-next-server: false三、消息發(fā)送:普通消息、同步 / 異步 / 單向發(fā)送
RocketMQ 支持同步發(fā)送、異步發(fā)送、單向發(fā)送三種消息發(fā)送方式,適用于不同的業(yè)務(wù)場(chǎng)景:
- 同步發(fā)送:發(fā)送后等待 Broker 響應(yīng),可靠性最高,適用于重要消息(如訂單創(chuàng)建)。
- 異步發(fā)送:發(fā)送后不阻塞,通過回調(diào)函數(shù)處理響應(yīng),適用于需要高吞吐量且允許少量延遲的場(chǎng)景。
- 單向發(fā)送:發(fā)送后不等待響應(yīng),性能最高,可靠性最低,適用于日志收集等不重要消息。
1. 封裝消息發(fā)送工具類
創(chuàng)建 RocketMQProducerService 類,注入 RocketMQTemplate(由 RocketMQ Starter 提供的模板類,簡(jiǎn)化消息發(fā)送),實(shí)現(xiàn)三種發(fā)送方式:
package com.example.demo.service;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.apache.rocketmq.spring.support.RocketMQHeaders;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* RocketMQ 生產(chǎn)者服務(wù)
*/
@Service
public class RocketMQProducerService {
// 注入 RocketMQ 模板類
@Resource
private RocketMQTemplate rocketMQTemplate;
/**
* 同步發(fā)送消息
* @param topic 主題名(可攜帶標(biāo)簽,格式:topic:tag)
* @param message 消息內(nèi)容
* @return 發(fā)送結(jié)果
*/
public SendResult sendSyncMessage(String topic, String message) {
// 構(gòu)建消息(可添加消息頭,如自定義 key)
Message<String> msg = MessageBuilder.withPayload(message)
.setHeader(RocketMQHeaders.KEYS, "sync-key-" + System.currentTimeMillis())
.build();
// 同步發(fā)送
return rocketMQTemplate.syncSend(topic, msg);
}
/**
* 異步發(fā)送消息
* @param topic 主題名
* @param message 消息內(nèi)容
*/
public void sendAsyncMessage(String topic, String message) {
Message<String> msg = MessageBuilder.withPayload(message)
.setHeader(RocketMQHeaders.KEYS, "async-key-" + System.currentTimeMillis())
.build();
// 異步發(fā)送,通過 SendCallback 處理回調(diào)
rocketMQTemplate.asyncSend(topic, msg, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
// 發(fā)送成功處理
System.out.println("異步發(fā)送消息成功:" + sendResult);
}
@Override
public void onException(Throwable e) {
// 發(fā)送失敗處理
System.err.println("異步發(fā)送消息失敗:" + e.getMessage());
}
});
}
/**
* 單向發(fā)送消息(不關(guān)心發(fā)送結(jié)果)
* @param topic 主題名
* @param message 消息內(nèi)容
*/
public void sendOneWayMessage(String topic, String message) {
Message<String> msg = MessageBuilder.withPayload(message)
.setHeader(RocketMQHeaders.KEYS, "oneway-key-" + System.currentTimeMillis())
.build();
// 單向發(fā)送
rocketMQTemplate.sendOneWay(topic, msg);
}
}2. 編寫測(cè)試接口
創(chuàng)建 MessageSendController 控制器,提供 HTTP 接口測(cè)試消息發(fā)送:
package com.example.demo.controller;
import org.apache.rocketmq.client.producer.SendResult;
import com.example.demo.service.RocketMQProducerService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* 消息發(fā)送測(cè)試控制器
*/
@RestController
@RequestMapping("/message")
public class MessageSendController {
@Resource
private RocketMQProducerService rocketMQProducerService;
// 測(cè)試同步發(fā)送
@GetMapping("/sync/send")
public String sendSyncMessage(@RequestParam String msg) {
// 主題名:demo-topic,標(biāo)簽:demo-tag(標(biāo)簽用于消息過濾)
String topic = "demo-topic:demo-tag";
SendResult sendResult = rocketMQProducerService.sendSyncMessage(topic, msg);
return "同步發(fā)送消息成功:" + sendResult;
}
// 測(cè)試異步發(fā)送
@GetMapping("/async/send")
public String sendAsyncMessage(@RequestParam String msg) {
String topic = "demo-topic:demo-tag";
rocketMQProducerService.sendAsyncMessage(topic, msg);
return "異步發(fā)送消息請(qǐng)求已提交";
}
// 測(cè)試單向發(fā)送
@GetMapping("/oneway/send")
public String sendOneWayMessage(@RequestParam String msg) {
String topic = "demo-topic:demo-tag";
rocketMQProducerService.sendOneWayMessage(topic, msg);
return "單向發(fā)送消息完成";
}
}四、消息消費(fèi):消費(fèi)者配置與消息監(jiān)聽
RocketMQ 的消費(fèi)端通過消息監(jiān)聽器監(jiān)聽指定主題的消息,Spring Boot 整合后可通過注解 @RocketMQMessageListener 快速實(shí)現(xiàn)消費(fèi)邏輯。
1. 編寫消息消費(fèi)者
創(chuàng)建 RocketMQConsumerService 類,實(shí)現(xiàn) RocketMQListener 接口,通過注解配置消費(fèi)者組、監(jiān)聽的主題和標(biāo)簽:
package com.example.demo.consumer;
import org.apache.rocketmq.spring.annotation.ConsumeMode;
import org.apache.rocketmq.spring.annotation.MessageModel;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Component;
/**
* RocketMQ 消費(fèi)者服務(wù)
* 注解說明:
* - consumerGroup:消費(fèi)者組名,必須唯一
* - topic:監(jiān)聽的主題名
* - selectorExpression:標(biāo)簽表達(dá)式,* 表示所有標(biāo)簽,也可指定具體標(biāo)簽(如 demo-tag)
* - messageModel:消息模式,CLUSTERING(集群模式)/BROADCASTING(廣播模式),默認(rèn)集群模式
* - consumeMode:消費(fèi)模式,CONCURRENTLY(并發(fā)消費(fèi))/ORDERLY(順序消費(fèi)),默認(rèn)并發(fā)消費(fèi)
*/
@Component
@RocketMQMessageListener(
consumerGroup = "demo-consumer-group",
topic = "demo-topic",
selectorExpression = "*",
messageModel = MessageModel.CLUSTERING,
consumeMode = ConsumeMode.CONCURRENTLY
)
public class RocketMQConsumerService implements RocketMQListener<String> {
/**
* 消息消費(fèi)邏輯
* @param message 消息內(nèi)容
*/
@Override
public void onMessage(String message) {
System.out.println("接收到消息:" + message);
// 模擬業(yè)務(wù)處理
// 注意:消費(fèi)端拋出異常會(huì)觸發(fā)消息重試
// handleBusiness(message);
}
/**
* 模擬業(yè)務(wù)處理
* @param message 消息內(nèi)容
*/
private void handleBusiness(String message) {
// 業(yè)務(wù)邏輯代碼
}
}2. 消費(fèi)者核心配置說明
- 消費(fèi)者組(consumerGroup):必須唯一,同一組的消費(fèi)者共同消費(fèi)主題的消息(集群模式下)。
- 消息模式(messageModel):
- CLUSTERING(集群模式):同組消費(fèi)者分?jǐn)傁M(fèi)消息,一條消息僅被一個(gè)消費(fèi)者消費(fèi),默認(rèn)模式。
- BROADCASTING(廣播模式):同組消費(fèi)者都會(huì)消費(fèi)同一條消息,適用于通知類消息(如配置更新)。
- 消費(fèi)模式(consumeMode):
- CONCURRENTLY(并發(fā)消費(fèi)):多線程并發(fā)消費(fèi),消費(fèi)速度快,默認(rèn)模式。
- ORDERLY(順序消費(fèi)):?jiǎn)尉€程消費(fèi),保證消息按順序消費(fèi),適用于有序消息場(chǎng)景(如訂單狀態(tài)變更)。
- 標(biāo)簽表達(dá)式(selectorExpression):用于過濾消息,支持
*(所有標(biāo)簽)、tag1 || tag2(多個(gè)標(biāo)簽)等表達(dá)式。
五、消息重試:消費(fèi)失敗后的重試機(jī)制
在實(shí)際業(yè)務(wù)中,消息消費(fèi)可能因網(wǎng)絡(luò)異常、業(yè)務(wù)處理失敗等原因失敗,RocketMQ 提供了消費(fèi)重試機(jī)制,確保消息被成功消費(fèi)。
1. 重試機(jī)制原理
- 默認(rèn)重試:當(dāng)消費(fèi)者消費(fèi)消息時(shí)拋出異常,RocketMQ 會(huì)將消息重新放入隊(duì)列,等待重試消費(fèi),默認(rèn)重試次數(shù)為 16 次(每次重試的間隔時(shí)間逐漸增加:1s、5s、10s、30s、1min、2min、3min、4min、5min、6min、7min、8min、9min、10min、20min、30min)。
- 死信隊(duì)列:當(dāng)消息重試 16 次后仍消費(fèi)失敗,會(huì)被發(fā)送到死信隊(duì)列(DLQ),死信隊(duì)列的命名規(guī)則為:
%DLQ%+消費(fèi)者組名,可通過消費(fèi)死信隊(duì)列的消息進(jìn)行人工處理。
2. 自定義重試配置與異常處理
(1)配置消費(fèi)重試次數(shù)
在 application.yml 中添加消費(fèi)者的重試配置(也可通過注解屬性配置):
# 消費(fèi)者重試配置(可在注解中覆蓋)
rocketmq:
consumer:
# 消費(fèi)線程數(shù)
consume-thread-max: 20
# 批量消費(fèi)的最大消息數(shù)
consume-message-batch-max-size: 1
# 消費(fèi)超時(shí)時(shí)間
consume-timeout: 15(2)手動(dòng)控制重試:返回消費(fèi)狀態(tài)
上述示例中,消費(fèi)者實(shí)現(xiàn)的是 RocketMQListener 接口,無法手動(dòng)控制消費(fèi)狀態(tài),若需要自定義重試邏輯,可實(shí)現(xiàn) RocketMQPushConsumerListener 接口(或使用 MessageListenerConcurrently),返回 ConsumeConcurrentlyStatus 枚舉:
package com.example.demo.consumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.apache.rocketmq.spring.core.RocketMQPushConsumerLifecycleListener;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 自定義重試邏輯的消費(fèi)者
*/
@Component
@RocketMQMessageListener(
consumerGroup = "demo-consumer-group-retry",
topic = "demo-topic",
selectorExpression = "*"
)
public class RetryRocketMQConsumerService implements RocketMQListener<MessageExt>, RocketMQPushConsumerLifecycleListener {
@Override
public void onMessage(MessageExt messageExt) {
String message = new String(messageExt.getBody());
System.out.println("接收到消息(帶重試邏輯):" + message + ",重試次數(shù):" + messageExt.getReconsumeTimes());
try {
// 模擬業(yè)務(wù)處理失敗
int a = 1 / 0;
// 業(yè)務(wù)處理成功,無需重試
} catch (Exception e) {
System.err.println("消息消費(fèi)失敗:" + e.getMessage());
// 若重試次數(shù)超過 3 次,直接返回成功(不再重試),否則拋出異常觸發(fā)重試
if (messageExt.getReconsumeTimes() >= 3) {
System.out.println("消息重試次數(shù)已達(dá)上限,不再重試");
// 可將消息記錄到數(shù)據(jù)庫(kù),后續(xù)人工處理
return;
}
// 拋出異常,觸發(fā)重試
throw new RuntimeException("消費(fèi)失敗,觸發(fā)重試");
}
}
@Override
public void prepareStart(org.apache.rocketmq.client.consumer.DefaultMQPushConsumer consumer) {
// 可自定義消費(fèi)者配置,如設(shè)置重試次數(shù)
try {
// 設(shè)置消費(fèi)線程數(shù)
consumer.setConsumeThreadMax(20);
// 設(shè)置消息監(jiān)聽器(若需要更細(xì)粒度的控制)
consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> {
for (MessageExt msg : msgs) {
onMessage(msg);
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
});
} catch (MQClientException e) {
throw new RuntimeException(e);
}
}
}3. 死信隊(duì)列處理
當(dāng)消息進(jìn)入死信隊(duì)列后,可創(chuàng)建專門的消費(fèi)者監(jiān)聽死信隊(duì)列,進(jìn)行人工干預(yù)處理:
package com.example.demo.consumer;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Component;
/**
* 死信隊(duì)列消費(fèi)者
* 死信隊(duì)列名稱:%DLQ% + 原消費(fèi)者組名
*/
@Component
@RocketMQMessageListener(
consumerGroup = "dlq-consumer-group",
topic = "%DLQ%demo-consumer-group",
selectorExpression = "*"
)
public class DlqRocketMQConsumerService implements RocketMQListener<String> {
@Override
public void onMessage(String message) {
System.out.println("接收到死信隊(duì)列消息:" + message);
// 人工處理邏輯,如記錄日志、通知運(yùn)維、手動(dòng)重試等
}
}六、測(cè)試驗(yàn)證
1. 啟動(dòng)項(xiàng)目
運(yùn)行 Spring Boot 項(xiàng)目的主類,確保 RocketMQ NameServer 和 Broker 已啟動(dòng)。
2. 發(fā)送消息測(cè)試
通過 HTTP 接口發(fā)送消息,例如:
- 同步發(fā)送:
http://localhost:8080/message/sync/send?msg=Hello RocketMQ Sync - 異步發(fā)送:
http://localhost:8080/message/async/send?msg=Hello RocketMQ Async - 單向發(fā)送:
http://localhost:8080/message/oneway/send?msg=Hello RocketMQ OneWay
3. 驗(yàn)證消費(fèi)與重試
觀察控制臺(tái)輸出,可看到消費(fèi)者成功接收消息;若在消費(fèi)端模擬業(yè)務(wù)異常(如除以 0),可看到消息重試的日志,重試次數(shù)達(dá)到上限后進(jìn)入死信隊(duì)列。
七、生產(chǎn)環(huán)境注意事項(xiàng)
- 主題與消費(fèi)者組規(guī)劃:提前手動(dòng)創(chuàng)建主題(關(guān)閉自動(dòng)創(chuàng)建),消費(fèi)者組名需唯一且有明確的業(yè)務(wù)含義。
- 消息重試配置:根據(jù)業(yè)務(wù)場(chǎng)景調(diào)整重試次數(shù)和間隔,避免無效重試占用資源。
- 死信隊(duì)列處理:建立死信隊(duì)列的監(jiān)控和處理機(jī)制,防止消息丟失。
- 消息冪等性:由于消息重試,消費(fèi)端需保證冪等性(如通過消息 key 去重)。
- 監(jiān)控與告警:接入 RocketMQ 監(jiān)控平臺(tái)(如 RocketMQ Dashboard),監(jiān)控消息發(fā)送 / 消費(fèi)情況,設(shè)置告警機(jī)制。
- 集群部署:生產(chǎn)環(huán)境中 RocketMQ 需采用集群部署,保證高可用。
八、總結(jié)
本文詳細(xì)介紹了 Spring Boot 整合 RocketMQ 的全流程,包括環(huán)境搭建、依賴配置、消息發(fā)送(同步 / 異步 / 單向)、消息消費(fèi)(集群 / 廣播、并發(fā) / 順序)、消息重試與死信隊(duì)列處理,并提供了完整的代碼示例。通過本文的實(shí)戰(zhàn)內(nèi)容,你可以快速掌握 RocketMQ 在 Spring Boot 項(xiàng)目中的核心使用方式,并根據(jù)實(shí)際業(yè)務(wù)場(chǎng)景進(jìn)行擴(kuò)展和優(yōu)化。RocketMQ 的功能遠(yuǎn)不止于此,后續(xù)還可深入學(xué)習(xí)順序消息、事務(wù)消息、延遲消息等高級(jí)特性,進(jìn)一步滿足復(fù)雜的業(yè)務(wù)需求。
到此這篇關(guān)于Spring Boot 整合 RocketMQ 的全流程(消息發(fā)送、消費(fèi)、重試)的文章就介紹到這了,更多相關(guān)Spring Boot 整合 RocketMQ內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java 數(shù)組ArrayList常用語(yǔ)法詳解
這篇文章主要介紹了Java 數(shù)組ArrayList常用語(yǔ)法詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09
淺談maven 多環(huán)境打包發(fā)布的兩種方式
這篇文章主要介紹了淺談maven 多環(huán)境打包發(fā)布的兩種方式,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-08-08
Java讀取resources中資源文件路徑以及jar中文件無法讀取的解決
這篇文章主要介紹了Java讀取resources中資源文件路徑以及jar中文件無法讀取的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05
在SpringBoot中更改默認(rèn)端口的方法總結(jié)
在本文中,小編將帶大家學(xué)習(xí)如何在 Spring Boot 中更改默認(rèn)端口,默認(rèn)情況下,嵌入式 Web 服務(wù)器使用 8080端口來啟動(dòng) Spring 引導(dǎo)應(yīng)用程序,有幾種方法可以更改該端口,文中介紹的非常詳細(xì),需要的朋友可以參考下2023-07-07
Java數(shù)據(jù)結(jié)構(gòu)之常見排序算法(上)
這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)之常見排序算法,本文章是匯總篇,且對(duì)每個(gè)排序都進(jìn)行了說明,可以很好的理清思路,對(duì)排序算法有個(gè)總體的框架,需要的朋友可以參考下2023-01-01
Spring Boot 直接用jar運(yùn)行項(xiàng)目的方法
這篇文章主要介紹了Spring Boot 直接用jar運(yùn)行項(xiàng)目的方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下2018-02-02
Java8中Lambda表達(dá)式使用和Stream API詳解
這篇文章主要給大家介紹了關(guān)于Java8中Lambda表達(dá)式使用和Stream API的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Java8具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05

