最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

RabbitMQ消息發(fā)送失敗的重試機制核心流程

 更新時間:2025年12月26日 09:06:22   作者:Wang's Blog  
本文介紹了基于NestJS和RabbitMQ的高可靠消息重試機制設(shè)計,通過三級保障機制(預(yù)持久化、實時回調(diào)處理、定時任務(wù)補償)和靈活的存儲層(支持MySQL/Redis),確保消息在發(fā)送失敗時能夠可靠重試,感興趣的朋友跟隨小編一起看看吧

核心問題

  • 確保消息在RabbitMQ投遞過程中的可靠性,通過持久化存儲、回調(diào)處理和定時重試解決網(wǎng)絡(luò)異常、服務(wù)宕機等場景下的消息丟失風(fēng)險
  • 解決分布式系統(tǒng)中消息發(fā)送失敗時的可靠重試,確保消息不丟失和最終一致性

重試機制核心流程

1 )消息發(fā)送前持久化

  • 原因:防止消息在發(fā)送過程中因服務(wù)崩潰或網(wǎng)絡(luò)異常丟失。
  • 實現(xiàn):調(diào)用發(fā)送接口時,先將消息存入數(shù)據(jù)庫,生成唯一ID(如UUID)記錄交換器、路由鍵、消息體及發(fā)送次數(shù)(初始為0)。

2 )消息發(fā)送后處理

  • 成功發(fā)送:
    • RabbitMQ確認接收(ACK)后,立即刪除數(shù)據(jù)庫中的持久化消息,避免數(shù)據(jù)膨脹。
  • 投遞失?。?ul>
  • 交換機不存在:觸發(fā)ConfirmCallback,標記發(fā)送失敗,等待重試。
  • 隊列不存在:觸發(fā)ReturnCallback,重新持久化消息到數(shù)據(jù)庫(原消息已刪除)。

3 )定時任務(wù)補償

  • 巡檢未成功消息:定時查詢數(shù)據(jù)庫中狀態(tài)為“待發(fā)送”且未超重試次數(shù)的消息。
  • 重試策略:
    • 重試次數(shù)+1,重新投遞消息。
    • 若超過最大重試次數(shù)(如5次),標記消息為“死亡” 并觸發(fā)告警(郵件/短信)。
  • 并發(fā)控制:多副本部署時需用分布式鎖(如Redis鎖)避免重復(fù)消費。

關(guān)鍵業(yè)務(wù)流程與 RabbitMQ 交互

  • Confirm 回調(diào)
    • 作用:確認 RabbitMQ 是否接收消息。
    • 邏輯:
      • 若收到 ACK → 刪除數(shù)據(jù)庫記錄。
      • 若未收到 ACK → 保留記錄等待重試。
  • Return 回調(diào)
    • 場景:消息被 RabbitMQ 接收但無法路由到隊列(如路由鍵錯誤)。
    • 處理:將消息重新持久化至數(shù)據(jù)庫,狀態(tài)保持 READY

NestJS 服務(wù)層實現(xiàn)

1 ) 消息存儲接口設(shè)計(TransMessageService

// trans-message.interface.ts
export interface TransMessageService {
  saveForSend(
    exchange: string,
    routingKey: string,
    payload: string
  ): Promise<TransMessagePO>;
  deleteOnAck(id: string): Promise<void>;
  saveOnReturn(
    id: string,
    exchange: string,
    routingKey: string,
    payload: string 
  ): Promise<TransMessagePO>;
  listPendingMessages(): Promise<TransMessagePO[]>;
  incrementRetryCount(id: string): Promise<void>;
  markAsDead(id: string): Promise<void>;
}

2 ) 數(shù)據(jù)庫實現(xiàn)(TypeORM + PostgreSQL)

// trans-message.service.ts 
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { TransMessagePO } from './trans-message.entity';
@Injectable()
export class DBTransMessageService implements TransMessageService {
  constructor(
    @InjectRepository(TransMessagePO)
    private readonly repo: Repository<TransMessagePO>,
    private readonly serviceName: string 
  ) {}
  async saveForSend(exchange: string, routingKey: string, payload: string) {
    const message = new TransMessagePO();
    message.id = uuidv4();
    message.serviceName = this.serviceName;
    message.exchange = exchange;
    message.routingKey = routingKey;
    message.payload = payload;
    message.retryCount = 0;
    message.status = 'PENDING';
    return this.repo.save(message);
  }
  async deleteOnAck(id: string) {
    await this.repo.delete({ id, serviceName: this.serviceName });
  }
  // 其他方法實現(xiàn)類似,略 
}

消息發(fā)送器(TransMessageSender)

1 ) 發(fā)送消息核心邏輯

// trans-message.sender.ts
import { Injectable, Logger } from '@nestjs/common';
import { RabbitMQService } from '@golevelup/nestjs-rabbitmq';
import { TransMessageService } from './trans-message.interface';
@Injectable()
export class TransMessageSender {
  private readonly logger = new Logger(TransMessageSender.name);
  constructor(
    private readonly rmqService: RabbitMQService,
    private readonly messageService: TransMessageService
  ) {}
  async send(exchange: string, routingKey: string, payload: any) {
    const payloadString = JSON.stringify(payload);
    try {
      // 1. 持久化到數(shù)據(jù)庫
      const messagePO = await this.messageService.saveForSend(
        exchange,
        routingKey,
        payloadString
      );
      // 2. 發(fā)送到RabbitMQ
      await this.rmqService.publish(exchange, routingKey, payload, {
        messageId: messagePO.id, // 關(guān)鍵:設(shè)置消息ID
        persistent: true
      });
      this.logger.log(`Message sent: ${messagePO.id}`);
    } catch (e) {
      this.logger.error(`Send failed: ${e.message}`, e.stack);
    }
  }
}

2 ) 回調(diào)處理(Confirm & Return)

// rabbitmq.config.ts
import { RabbitMQModule } from '@golevelup/nestjs-rabbitmq';
@Module({
  imports: [
    RabbitMQModule.forRoot(RabbitMQModule, {
      exchanges: [{ name: 'orders', type: 'topic' }],
      uri: 'amqp://localhost',
      connectionInitOptions: { wait: false },
      // 注冊回調(diào)函數(shù)
      setupController: (channel) => {
        channel.on('return', (msg) => this.handleReturn(msg));
        channel.on('ack', (msg) => this.handleAck(msg));
      }
    })
  ]
})
export class AppModule {
  handleReturn(msg: ConsumeMessage) {
    const { exchange, routingKey } = msg.fields;
    const payload = msg.content.toString();
    const messageId = msg.properties.messageId; // 關(guān)鍵:獲取消息ID
    this.messageService.saveOnReturn(messageId, exchange, routingKey, payload);
  }
  handleAck(msg: ConsumeMessage) {
    const messageId = msg.properties.messageId;
    this.messageService.deleteOnAck(messageId);
  }
}

定時任務(wù)與重試控制

// retry.task.ts
import { Injectable, Logger } from '@nestjs/common';
import { SchedulerRegistry } from '@nestjs/schedule';
@Injectable()
export class RetryTask {
  private readonly logger = new Logger(RetryTask.name);
  private readonly MAX_RETRY = 5;
  constructor(
    private messageService: TransMessageService,
    private scheduler: SchedulerRegistry
  ) {
    this.startRetryCycle();
  }
  startRetryCycle() {
    const interval = setInterval(async () => {
      const messages = await this.messageService.listPendingMessages();
      for (const msg of messages) {
        if (msg.retryCount >= this.MAX_RETRY) {
          await this.messageService.markAsDead(msg.id);
          this.triggerAlert(`Message dead: ${msg.id}`);
          continue;
        }
        await this.messageService.incrementRetryCount(msg.id);
        await this.resendMessage(msg);
      }
    }, 60_000); // 每分鐘執(zhí)行 
    this.scheduler.addInterval('retry-job', interval);
  }
  private async resendMessage(msg: TransMessagePO) {
    // 調(diào)用發(fā)送器重新發(fā)送(略)
  }
}

NestJS 核心代碼實現(xiàn)

  1. 消息持久化服務(wù)層(TransMessageService
// trans-message.service.ts
import { Injectable } from '@nestjs/common';
import { TransMessage } from './entity/trans-message.entity';
import { Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { MessageType } from './enums/message-type.enum';
@Injectable()
export class TransMessageService {
  constructor(
    @InjectRepository(TransMessage)
    private readonly messageRepo: Repository<TransMessage>,
    private readonly serviceName: string, // 注入服務(wù)標識
  ) {}
  // 發(fā)送前持久化
  async createReadyMessage(
    exchange: string,
    routingKey: string,
    payload: string,
  ): Promise<TransMessage> {
    const message = this.messageRepo.create({
      id: uuidv4(),
      service: this.serviceName,
      exchange,
      routingKey,
      payload,
      sendDate: new Date(),
      sequence: 0,
      type: MessageType.READY,
    });
    return this.messageRepo.save(message);
  }
  // 發(fā)送成功刪除記錄 
  async markMessageSuccess(id: string): Promise<void> {
    await this.messageRepo.delete({ id, service: this.serviceName });
  }
  // 消息路由失敗后重新持久化
  async recreateReturnedMessage(
    exchange: string,
    routingKey: string,
    payload: string,
  ): Promise<TransMessage> {
    return this.createReadyMessage(exchange, routingKey, payload);
  }
  // 查詢待重試消息
  async listReadyMessages(): Promise<TransMessage[]> {
    return this.messageRepo.find({
      where: { type: MessageType.READY, service: this.serviceName },
    });
  }
  // 遞增重試次數(shù)
  async incrementRetryCount(id: string): Promise<void> {
    const message = await this.messageRepo.findOneBy({ id });
    if (message) {
      message.sequence += 1;
      await this.messageRepo.save(message);
    }
  }
  // 標記消息為死亡狀態(tài)
  async markMessageDead(id: string): Promise<void> {
    const message = await this.messageRepo.findOneBy({ id });
    if (message) {
      message.type = MessageType.DEAD;
      await this.messageRepo.save(message);
    }
  }
}
  1. 消息發(fā)送器(TransMessageSender
// trans-message.sender.ts
import { Injectable, Logger } from '@nestjs/common';
import { RabbitMQService } from '@golevelup/nestjs-rabbitmq';
import { TransMessageService } from './trans-message.service';
@Injectable()
export class TransMessageSender {
  private readonly logger = new Logger(TransMessageSender.name);
  constructor(
    private readonly rmqService: RabbitMQService,
    private readonly transMessageService: TransMessageService,
  ) {}
  async send(exchange: string, routingKey: string, payload: object): Promise<void> {
    try {
      // 1. 序列化消息
      const payloadString = JSON.stringify(payload);
      // 2. 持久化到數(shù)據(jù)庫
      const message = await this.transMessageService.createReadyMessage(
        exchange,
        routingKey,
        payloadString,
      );
      // 3. 發(fā)送至 RabbitMQ
      await this.rmqService.publish(exchange, routingKey, payload, {
        messageId: message.id,
        contentType: 'application/json',
      });
      this.logger.log(`Message sent: ${message.id}`);
    } catch (e) {
      this.logger.error(`Send failed: ${e.message}`, e.stack);
    }
  }
}
  1. RabbitMQ 回調(diào)處理
// rmq.config.ts
import { RabbitMQModule } from '@golevelup/nestjs-rabbitmq';
import { TransMessageService } from './trans-message.service';
@Module({
  imports: [
    RabbitMQModule.forRoot(RabbitMQModule, {
      exchanges: [{ name: 'orders', type: 'topic' }],
      uri: 'amqp://localhost:5672',
      connectionInitOptions: { wait: false },
      // 注冊回調(diào)處理器 
      setupController: (channel) => {
        // 確認回調(diào) 
        channel.on('ack', (msg) => {
          const messageId = msg.properties.messageId;
          this.transMessageService.markMessageSuccess(messageId);
        });
        // 返回回調(diào)
        channel.on('return', (msg) => {
          const { exchange, routingKey } = msg.fields;
          const payload = msg.content.toString();
          this.transMessageService.recreateReturnedMessage(
            exchange,
            routingKey,
            payload,
          );
        });
      },
    }),
  ],
})
export class RmqConfigModule {}
  • 消息預(yù)持久化機制
    • 發(fā)送前必須將消息持久化到數(shù)據(jù)庫,防止發(fā)送過程中因網(wǎng)絡(luò)中斷或服務(wù)崩潰導(dǎo)致消息丟失。業(yè)務(wù)系統(tǒng)調(diào)用發(fā)送接口時:
    • 發(fā)送成功后的清理邏輯
  • 當 RabbitMQ 確認(ACK)接收消息后,立即刪除數(shù)據(jù)庫中的持久化記錄,避免無效數(shù)據(jù)堆積引發(fā)存儲壓力。
    • 定時任務(wù)重試策略
    • 獨立進程定時掃描狀態(tài)為 PENDING 的消息:
    • 檢查重試次數(shù)是否超限(如 ≤5次)
  • 每次重試增加 retryCount
  • 超限則標記為 DEAD 并觸發(fā)告警

工程示例:1

1 ) 方案1:基礎(chǔ)持久化+重試(推薦)

  • 適用場景:中小型系統(tǒng)
  • 技術(shù)棧:
    • @golevelup/nestjs-rabbitmq + TypeORM + PostgreSQL
    • 消息表字段:id, serviceName, exchange, routingKey, payload, retryCount, status
  • 優(yōu)勢:實現(xiàn)簡單,依賴少

2 ) 方案2:Redis 高性能存儲

// redis-trans-message.service.ts
import { RedisService } from '@liaoliaots/nestjs-redis';
@Injectable()
export class RedisTransMessageService implements TransMessageService {
  private readonly KEY_PREFIX = 'msg:';
  constructor(private redisService: RedisService) {}
  async saveForSend(exchange: string, routingKey: string, payload: string) {
    const id = uuidv4();
    const client = this.redisService.getClient();
    await client.hset(`${this.KEY_PREFIX}${id}`, {
      exchange,
      routingKey,
      payload,
      retryCount: '0',
      status: 'PENDING'
    });
    return { id } as TransMessagePO;
  }
  // 其他方法通過Redis HSET/HGET/DEL實現(xiàn) 
}

3 ) 方案3:分布式事務(wù)框架集成

  • 技術(shù)棧:NestJS + RabbitMQ + Transactional Outbox 模式
  • 核心邏輯:
    • 業(yè)務(wù)操作與消息持久化在同一個數(shù)據(jù)庫事務(wù)中提交
    • 獨立進程輪詢Outbox表并投遞消息
  • 優(yōu)勢:強一致性,避免業(yè)務(wù)成功但消息未存儲

工程示例:2

1 ) 方案 1:基礎(chǔ)數(shù)據(jù)庫重試

// task.service.ts 
@Injectable()
export class RetryTaskService {
  constructor(private readonly transMessageService: TransMessageService) {}
  @Cron('*/5 * * * * *') // 每5秒執(zhí)行
  async handleRetry() {
    const messages = await this.transMessageService.listReadyMessages();
    messages.forEach(async (msg) => {
      if (msg.sequence < 5) {
        await this.transMessageService.incrementRetryCount(msg.id);
        // 重新發(fā)送邏輯(略)
      } else {
        await this.transMessageService.markMessageDead(msg.id);
        // 觸發(fā)告警(略)
      }
    });
  }
}

2 ) 方案 2:Redis 高性能暫存

優(yōu)勢:

  • 讀寫速度比 MySQL 快 10 倍以上
  • 支持分布式鎖解決多副本并發(fā)問題
// 使用 Redis 存儲消息
import { Redis } from 'ioredis';
@Injectable()
export class RedisTransMessageService implements TransMessageService {
  private readonly redis = new Redis();
  async createReadyMessage(
    exchange: string,
    routingKey: string,
    payload: string,
  ): Promise<TransMessage> {
    const id = uuidv4();
    await this.redis.hset(
      `msg:${id}`,
      'payload', payload,
      'exchange', exchange,
      'routingKey', routingKey,
      'sequence', '0',
    );
    return { id, exchange, routingKey, payload, sequence: 0 };
  }
}

3 ) 方案 3:死信隊列(DLX)自動重試

RabbitMQ 配置命令:

創(chuàng)建死信交換機和隊列
rabbitmqadmin declare exchange name=dlx type=direct
rabbitmqadmin declare queue name=dead_messages
rabbitmqadmin declare binding source=dlx destination=dead_messages routing_key=dead
主隊列綁定死信路由
rabbitmqadmin declare queue name=orders \
  arguments='{"x-dead-letter-exchange":"dlx", "x-dead-letter-routing-key":"dead"}'

NestJS 消費死信消息:

@RabbitSubscribe({
  exchange: 'dlx',
  routingKey: 'dead',
  queue: 'dead_messages',
})
async handleDeadMessage(msg: any) {
  // 解析原始消息ID并重新持久化
  const originalMsgId = msg.properties.headers['x-original-message-id'];
  await this.transMessageService.recreateReturnedMessage(
    msg.fields.exchange,
    msg.fields.routingKey,
    msg.content.toString(),
  );
}

工程示例:3

1 ) 方案1:數(shù)據(jù)庫存儲方案(TypeORM)

// trans-message.service.ts
@Injectable()
export class TransMessageService {
  constructor(
    @InjectRepository(TransMessage)
    private readonly messageRepo: Repository<TransMessage>
  ) {}
  async prePersist(exchange: string, routingKey: string, payload: string) {
    const message = this.messageRepo.create({
      exchange,
      routingKey,
      payload,
      status: 'PENDING'
    });
    return this.messageRepo.save(message);
  }
  async markAsSuccess(id: string) {
    await this.messageRepo.delete(id);
  }
}

2 ) 方案2:Redis 高性能存儲方案

// redis-trans.service.ts
import { RedisService } from '@liaoliaots/nestjs-redis';
@Injectable()
export class RedisTransService {
  constructor(private readonly redisService: RedisService) {}
  async prePersist(exchange: string, routingKey: string, payload: string) {
    const client = this.redisService.getClient();
    const id = uuidv4();
    await client.hset(
      `msg:${id}`,
      'exchange', exchange,
      'routingKey', routingKey,
      'payload', payload,
      'status', 'PENDING'
    );
    return id;
  }
}

3 ) 方案3:混合存儲方案(數(shù)據(jù)庫+Redis)

  • 熱數(shù)據(jù):高頻重試消息存 Redis
  • 冷數(shù)據(jù):超限消息轉(zhuǎn)存數(shù)據(jù)庫供審計
  • 一致性保障:通過 Redis 事務(wù)確保狀態(tài)同步

關(guān)鍵配置與命令

RabbitMQ 必要設(shè)置

啟用持久化交換機和隊列
rabbitmqctl set_policy HA ".*" '{"ha-mode":"all"}' --apply-to all
監(jiān)控命令
rabbitmqctl list_queues name messages_ready messages_unacknowledged

NestJS 模塊配置

// app.module.ts
@Module({
  imports: [
    TypeOrmModule.forFeature([TransMessagePO]),
    RabbitMQModule.forRootAsync(RabbitMQModule, {
      useFactory: () => ({
        uri: process.env.RABBITMQ_URI,
        exchanges: [{ name: 'orders', type: 'topic', durable: true }]
      })
    })
  ],
  providers: [
    { provide: TransMessageService, useClass: DBTransMessageService },
    TransMessageSender,
    RetryTask
  ]
})
export class AppModule {}

RabbitMQ 周邊配置處理

1 ) NestJS 連接配置

// rabbitmq.module.ts
import { RabbitMQModule } from '@golevelup/nestjs-rabbitmq';
@Module({
  imports: [
    RabbitMQModule.forRoot(RabbitMQModule, {
      exchanges: [{ name: 'orders', type: 'topic' }],
      uri: 'amqp://user:pass@localhost:5672',
      connectionInitOptions: { wait: false }
    })
  ]
})
export class RabbitModule {}

2 ) 關(guān)鍵 Shell 命令

創(chuàng)建帶持久化的交換機
rabbitmqadmin declare exchange name=orders type=topic durable=true
監(jiān)控未路由消息
rabbitmqctl list_queues name messages_unroutable

3 ) 告警機制實現(xiàn)

// alert.service.ts
@Injectable()
export class AlertService {
  async triggerAlert(messageId: string) {
    // 集成郵件/Slack/Webhook
    await slackService.send(`消息 ${messageId} 重試超限!`);
  }
}

核心優(yōu)化點

  1. 消息軌跡追蹤
    通過 properties.messageId 實現(xiàn)全鏈路消息關(guān)聯(lián)
  2. 并發(fā)控制
    使用 Redis 分布式鎖防止多副本重試沖突:
    import Redlock from 'redlock';
    const lock = await redlock.acquire([`lock:${messageId}`], 5000);
    
  3. 退避策略
    指數(shù)級延長重試間隔:delay = Math.min(2 retryCount * 1000, 60000)

關(guān)鍵設(shè)計原則:

  • 所有消息操作必須冪等
  • 持久化存儲與 MQ 狀態(tài)需原子性同步
  • 死信消息必須提供人工干預(yù)接口

補充知識點

  1. RabbitMQ 持久化機制
    • 消息需設(shè)置 deliveryMode: 2
    • 隊列聲明時添加 durable: true
  2. NestJS 微服務(wù)模式
    // main.ts 啟用混合模式
    app.connectMicroservice<RabbitMQTransportOptions>({
      transport: Transport.RMQ,
      options: { urls: ['amqp://...'], queue: 'retry_queue' }
    });
    
  3. 監(jiān)控指標
    • 重試成功率
    • 平均重試耗時
    • 死信隊列堆積量

關(guān)鍵問題解決方案

并發(fā)重試控制

const lockKey = `lock:msg:${msg.id}`;
const lock = await redis.set(lockKey, '1', 'EX', 30, 'NX');
if (lock) { /* 執(zhí)行重試 */ }

使用 Redis 分布式鎖確保多副本服務(wù)不會重復(fù)處理同一條消息:

消息冪等性設(shè)計

@RabbitSubscribe({ exchange: 'orders', routingKey: 'order.create' })
async handleOrderEvent(msg: any, @Message() amqpMsg) {
  const messageId = amqpMsg.properties.messageId;
  if (await this.redis.exists(`processed:${messageId}`)) return;
  // 處理業(yè)務(wù)...
}
  • 在消費者端通過 messageId 去重,避免重復(fù)消費:
  • 性能優(yōu)化
    • 批量處理:定時任務(wù)每次拉取 100 條消息減少 DB 查詢次數(shù)。
    • 異步刪除:成功確認后使用 setImmediate 異步刪除記錄避免阻塞主線程。

注意事項

  1. 消息完整性:
    • 必須設(shè)置messageIdpersistent: true確保RabbitMQ端持久化。
  2. 重試設(shè)計:
    • 采用指數(shù)退避策略(如1s/5s/30s)避免雪崩。
  3. 死信處理:
    • 建議將死信轉(zhuǎn)入獨立隊列人工干預(yù)。
  4. 性能優(yōu)化:
    • 批量查詢待重試消息(如每次100條),減少DB壓力

關(guān)鍵點:通過數(shù)據(jù)庫/REDIS雙寫、ACK回調(diào)聯(lián)動、定時補償三位一體,實現(xiàn)消息的可靠投遞,適用于訂單支付、庫存同步等高可靠性場景

總結(jié)

本文實現(xiàn)了基于 NestJS + RabbitMQ 的高可靠消息重試架構(gòu),核心創(chuàng)新點:

  1. 三級保障機制:預(yù)持久化 → 實時回調(diào)處理 → 定時任務(wù)補償。
  2. 靈活存儲層:支持 MySQL/Redis 無縫切換,適應(yīng)不同規(guī)模業(yè)務(wù)。
  3. 生產(chǎn)級方案:提供數(shù)據(jù)庫重試、Redis 高性能方案、死信隊列三種工程實現(xiàn)。

關(guān)鍵提示:

  • 重試閾值建議設(shè)為 3-5次,避免無限重試拖垮系統(tǒng)。
  • 使用 x-delay 插件實現(xiàn)指數(shù)退避重試(如 1s/3s/10s)。
  • 監(jiān)控 DEAD 狀態(tài)消息并及時介入處理。

到此這篇關(guān)于RabbitMQ: 消息發(fā)送失敗的重試機制設(shè)計與實現(xiàn)的文章就介紹到這了,更多相關(guān)RabbitMQ 消息重試機制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Idea提交代碼到gitee上實現(xiàn)方式

    Idea提交代碼到gitee上實現(xiàn)方式

    本文詳細介紹了使用Gitee和Git進行項目創(chuàng)建、提交、拉取和回滾的具體步驟,包括本地與遠程倉庫的操作方法,以及常用Git命令的總結(jié)和注意事項
    2025-10-10
  • Spring?RestTemplate如何利用攔截器打印請求參數(shù)和返回狀態(tài)

    Spring?RestTemplate如何利用攔截器打印請求參數(shù)和返回狀態(tài)

    這篇文章主要介紹了Spring?RestTemplate如何利用攔截器打印請求參數(shù)和返回狀態(tài)問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • idea啟動項目報端口號沖突或被占用的解決方法

    idea啟動項目報端口號沖突或被占用的解決方法

    這篇文章主要介紹了idea啟動項目報端口號沖突或被占用的解決方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-10-10
  • JAVA 中解密RSA算法JS加密實例詳解

    JAVA 中解密RSA算法JS加密實例詳解

    這篇文章主要介紹了JAVA 中解密RSA算法JS加密 的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • Java環(huán)境配置圖文教程(推薦)

    Java環(huán)境配置圖文教程(推薦)

    下面小編就為大家?guī)硪黄狫ava環(huán)境配置圖文教程(推薦)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • 解讀easyexcel中的常用注解

    解讀easyexcel中的常用注解

    這篇文章主要介紹了關(guān)于easyexcel中的常用注解,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • 簡單了解Java斷言利器AssertJ原理及用法

    簡單了解Java斷言利器AssertJ原理及用法

    這篇文章主要介紹了簡單了解Java斷言利器AssertJ原理及用法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-11-11
  • SpringBoot中的三種應(yīng)用事件處理機制詳解

    SpringBoot中的三種應(yīng)用事件處理機制詳解

    在項目開發(fā)中,組件間的松耦合設(shè)計至關(guān)重要,應(yīng)用事件處理機制作為觀察者模式的一種實現(xiàn),允許系統(tǒng)在保持模塊獨立性的同時實現(xiàn)組件間的通信,SpringBoot延續(xù)并增強了Spring框架的事件機制,提供了多種靈活的事件處理方式,本文給大家介紹了SpringBoot中的三種應(yīng)用事件處理機制
    2025-04-04
  • springboot添加多數(shù)據(jù)源的方法實例教程

    springboot添加多數(shù)據(jù)源的方法實例教程

    這篇文章主要給大家介紹了關(guān)于springboot添加多數(shù)據(jù)源方法的相關(guān)資料,在實際開發(fā)中經(jīng)??赡苡龅皆谝粋€應(yīng)用中可能要訪問多個數(shù)據(jù)庫多的情況,需要的朋友可以參考下
    2023-09-09
  • SpringBoot使用AOP切面對請求進行日志記錄方式

    SpringBoot使用AOP切面對請求進行日志記錄方式

    這篇文章主要介紹了SpringBoot使用AOP切面對請求進行日志記錄方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-05-05

最新評論

玛纳斯县| 敖汉旗| 会同县| 光山县| 通道| 铜陵市| 中卫市| 桂阳县| 长子县| 贵州省| 隆化县| 无锡市| 栖霞市| 武陟县| 内黄县| 苍溪县| 钟山县| 老河口市| 达日县| 无极县| 保德县| 抚松县| 峨边| 汤原县| 浮梁县| 安图县| 轮台县| 息烽县| 泗洪县| 西乡县| 通海县| 遂昌县| 楚雄市| 建阳市| 合阳县| 滦平县| 都昌县| 伽师县| 林西县| 宁明县| 宜宾县|