🔥
Caster 開發日誌
  • Java
    • JVM Performance Tool
      • Java Debug Wire Protocol (JDWP) 的詳細介紹
      • JConsole 詳細介紹
    • Spring Boot
      • Spring Security
      • Spring Boot Admin
      • Spring Event
      • Spring AOP
      • Spring Boot JUnit 5
      • Apache Dubbo
    • Reflect 應用
    • ELK + F 建構
    • Socket.IO
    • OCR - 光學字元辨識
    • 讀取JAR resource文件
    • LocalTime & MySQL時間精度
    • Gradle multi module
    • MyBatis-Plus
    • Java Date operation
    • Java IP to Long
    • Apache Commons lang3 應用
      • Function 應用
    • Cloud Platform
      • Amazon S3
        • SDK V1
          • Bucket
        • SDK V2
          • Bucket
      • Google Cloud Platform
      • Azure Cloud
        • Storage
      • OVHcloud
        • Config
    • SSL/TLS工具
    • Util 工具
      • Jackson Json工具
      • Charles應用
      • JMeter – Performing Distributed Load Testing with Docker
    • Redis
      • Stream
      • Redisson 分布式鎖機制
      • Create Redis Cluster Using Docker
      • List Operations
    • Java 8
      • method & constructor Reference
      • CompletableFuture
      • FunctionInterface
      • Stream 應用
      • 繁簡轉換 - 簡易調整
    • MySQL
      • 建立測試用 流水號Table
      • SQL 效能調校 - Explain
      • SQL 效能調校 - Partition
      • 排程 - Event
    • Apache ShardingSphere
  • Kubernetes
    • 初入江湖(K8S)
    • 零中斷服務滾動更新
    • Kubernetes DNS
    • Ingress & Ingress Controller 教學
    • Ingress TLS Easy setup
  • 指令集
  • Telegram
  • SourceTree
    • 踩坑紀錄(ㄧ) - Git Flow
    • 踩坑紀錄(二) - 修改檔名
  • 專案統計
    • Robot
    • Recharge
  • GitHub
    • Actions
  • GitLab
    • 介紹 GitLab
    • 使用 Docker 自架 GitLab
    • 簡介 GitLab CI/CD
      • GitLab Runner 詳細介紹與設定方式
Powered by GitBook
On this page
  • 簡單實作
  • 同時有多個Listener
  • 自訂排序Listener執行順序 ( @order)
  • Default 為同步處理
  • 修改為非同步
  1. Java
  2. Spring Boot

Spring Event

Spring 應用程式事件允許我們傳送和接收特定應用程式事件,我們可以根據需要處理這些事件。事件用於在鬆散耦合的元件之間交換資訊。由於釋出者和訂閱者之間沒有直接耦合,因此可以在不影響釋出者的情況下修改訂閱者,反之亦然。 其實就是觀察者模式,我看到一個不錯的例子描述觀察者模式的概念。 Ex.在年代較早以前,去銀行臨櫃領現大家都是需要一個一個排隊,大排長龍等待櫃台處理,但是當出現了叫號機,來銀行領現的人都會先去取號等待櫃檯叫號,在等待叫號的期間可以先去處理自己的事情。 叫號機,相當於事件發布器(事件註冊中心) 客戶,相當於事件源 櫃檯,相當於一個事件監聽器 想當而然 Spring 不想放過這麼好的設計模式。

如上所述,面向事件的編程(也稱作事件驅動編程)是基於對消息信號的反應的編程。 面向事件編程需要滿三個條件:

  • 事件源(ApplicationEvent):消息的源頭,如點擊一個按鈕、訪問某個頁面、新增一條數據等。

  • 事件註冊中心(ApplicationEventPublisher):事件註冊中心用於存儲和發布事件。

  • 事件監聽器(ApplicationListener):用於接收特定的消息,並作出對應的反應。

簡單實作

Event

@Getter
@Setter
public class DemoEvent extends ApplicationEvent {
    private Long id;
    private String message;

    public DemoEvent(Object source, Long id, String message) {
        super(source);
        this.id = id;
        this.message = message;
    }
}

Listener

public class DemoListener {
	@EventListener
	public void firstEvent(DemoEvent demoEvent) {
		System.out.println(">>>>>>>>> firstEvent");
		System.out.println("收到了:" + demoEvent.getSource() + "訊息;時間:" + demoEvent.getTimestamp());
		System.out.println("訊息:" + demoEvent.getId() + ":" + demoEvent.getMessage());
	}
}

Publisher

@Component
public class DemoPublisher implements ApplicationEventPublisherAware {

	private ApplicationEventPublisher applicationEventPublisher;

	@Override
	public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
		this.applicationEventPublisher = applicationEventPublisher;
	}

	public void testEvent() {
		applicationEventPublisher.publishEvent(new DemoEvent("DemoEvent", 1l, "Text123456"));
	}
}

Controller

@RestController
@RequestMapping(value = "/event")
public class EventController {
	@Autowired
	DemoPublisher demoPublisher;

	@GetMapping("/")
	public ResponseEntity testEventApi() {
		demoPublisher.testEvent();
		return ResponseEntity.ok(JSONResult.createResult(SuccessCodeMsg.COMMON_OK));
	}
}
>>>>>>>>> firstEvent
收到了:DemoEvent訊息;時間:1646215660237
訊息:1:Text123456

同時有多個Listener

Listener

@Component
public class DemoListener {
	@EventListener
	public void secondEvent(DemoEvent demoEvent) {
		System.out.println(">>>>>>>>> secondEvent");
		System.out.println("收到了:" + demoEvent.getSource() + "訊息;時間:" + demoEvent.getTimestamp());
		System.out.println("訊息:" + demoEvent.getId() + ":" + demoEvent.getMessage());
	}

	@EventListener
	public void otherEvent(DemoEvent demoEvent) {
		System.out.println(">>>>>>>>> otherEvent");
		System.out.println("收到了:" + demoEvent.getSource() + "訊息;時間:" + demoEvent.getTimestamp());
		System.out.println("訊息:" + demoEvent.getId() + ":" + demoEvent.getMessage());
	}

	@EventListener
	public void firstEvent(DemoEvent demoEvent) {
		System.out.println(">>>>>>>>> firstEvent");
		System.out.println("收到了:" + demoEvent.getSource() + "訊息;時間:" + demoEvent.getTimestamp());
		System.out.println("訊息:" + demoEvent.getId() + ":" + demoEvent.getMessage());
	}
}

output

>>>>>>>>> secondEvent
收到了:DemoEvent訊息;時間:1646216147911
訊息:1:Text123456
>>>>>>>>> otherEvent
收到了:DemoEvent訊息;時間:1646216147911
訊息:1:Text123456
>>>>>>>>> firstEvent
收到了:DemoEvent訊息;時間:1646216147911
訊息:1:Text123456

自訂排序Listener執行順序 ( @order)

Listener

@Component
public class DemoListener {
	@Order(1)
	@EventListener
	public void secondEvent(DemoEvent demoEvent) {
		System.out.println(">>>>>>>>> secondEvent");
		System.out.println("收到了:" + demoEvent.getSource() + "訊息;時間:" + demoEvent.getTimestamp());
		System.out.println("訊息:" + demoEvent.getId() + ":" + demoEvent.getMessage());
	}
	@Order
	@EventListener
	public void otherEvent(DemoEvent demoEvent) {
		System.out.println(">>>>>>>>> otherEvent");
		System.out.println("收到了:" + demoEvent.getSource() + "訊息;時間:" + demoEvent.getTimestamp());
		System.out.println("訊息:" + demoEvent.getId() + ":" + demoEvent.getMessage());
	}
	@Order(2)
	@EventListener
	public void firstEvent(DemoEvent demoEvent) {
		System.out.println(">>>>>>>>> firstEvent");
		System.out.println("收到了:" + demoEvent.getSource() + "訊息;時間:" + demoEvent.getTimestamp());
		System.out.println("訊息:" + demoEvent.getId() + ":" + demoEvent.getMessage());
	}
}

output

>>>>>>>>> secondEvent
收到了:DemoEvent訊息;時間:1646216288988
訊息:1:Text123456
>>>>>>>>> firstEvent
收到了:DemoEvent訊息;時間:1646216288988
訊息:1:Text123456
>>>>>>>>> otherEvent
收到了:DemoEvent訊息;時間:1646216288988
訊息:1:Text123456

Default 為同步處理

經Postman 執行時間統計 原先沒有Sleep -> 執行時間 358ms 加上Thread sleep -> 執行時間 3.31s

Listener

@Component
public class DemoListener {
	@EventListener
	public void secondEvent(DemoEvent demoEvent) {
		System.out.println(">>>>>>>>> secondEvent");
		for (int i = 0; i < 3; i++) {
			try {
				System.out.println(">>>>>>>>>Sleeping ~~ >>>>>>>>>>>>>>>>>>>>>>>>>>>>");
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("收到了:" + demoEvent.getSource() + "訊息;時間:" + demoEvent.getTimestamp());
		System.out.println("訊息:" + demoEvent.getId() + ":" + demoEvent.getMessage());
	}
	@EventListener
	public void otherEvent(DemoEvent demoEvent) {
		System.out.println(">>>>>>>>> otherEvent");
		System.out.println("收到了:" + demoEvent.getSource() + "訊息;時間:" + demoEvent.getTimestamp());
		System.out.println("訊息:" + demoEvent.getId() + ":" + demoEvent.getMessage());
	}
	@EventListener
	public void firstEvent(DemoEvent demoEvent) {
		System.out.println(">>>>>>>>> firstEvent");
		System.out.println("收到了:" + demoEvent.getSource() + "訊息;時間:" + demoEvent.getTimestamp());
		System.out.println("訊息:" + demoEvent.getId() + ":" + demoEvent.getMessage());
	}
}

output

>>>>>>>>> secondEvent
>>>>>>>>>Sleeping ~~ >>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>Sleeping ~~ >>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>Sleeping ~~ >>>>>>>>>>>>>>>>>>>>>>>>>>>>
收到了:DemoEvent訊息;時間:1646216488728
訊息:1:Text123456
>>>>>>>>> otherEvent
收到了:DemoEvent訊息;時間:1646216488728
訊息:1:Text123456
>>>>>>>>> firstEvent
收到了:DemoEvent訊息;時間:1646216488728
訊息:1:Text123456

修改為非同步

Listener

@Async
@Component
public class DemoListener {
	@EventListener
	public void secondEvent(DemoEvent demoEvent) {
		System.out.println(">>>>>>>>> secondEvent");
		System.out.println("收到了:" + demoEvent.getSource() + "訊息;時間:" + demoEvent.getTimestamp());
		System.out.println("訊息:" + demoEvent.getId() + ":" + demoEvent.getMessage());
	}
	@EventListener
	public void otherEvent(DemoEvent demoEvent) {
		System.out.println(">>>>>>>>> otherEvent");
		System.out.println("收到了:" + demoEvent.getSource() + "訊息;時間:" + demoEvent.getTimestamp());
		System.out.println("訊息:" + demoEvent.getId() + ":" + demoEvent.getMessage());
	}
	@EventListener
	public void firstEvent(DemoEvent demoEvent) {
		System.out.println(">>>>>>>>> firstEvent");
		System.out.println("收到了:" + demoEvent.getSource() + "訊息;時間:" + demoEvent.getTimestamp());
		System.out.println("訊息:" + demoEvent.getId() + ":" + demoEvent.getMessage());
	}
}

output

>>>>>>>>> secondEvent
>>>>>>>>> firstEvent
>>>>>>>>> otherEvent
收到了:DemoEvent訊息;時間:1646216104512
收到了:DemoEvent訊息;時間:1646216104512
收到了:DemoEvent訊息;時間:1646216104512
訊息:1:Text123456
訊息:1:Text123456
訊息:1:Text123456

參考網站:

PreviousSpring Boot AdminNextSpring AOP

Last updated 1 year ago

output ( call Api >> )

http://localhost:8080/event/
https://segmentfault.com/a/1190000022348275
https://www.baeldung.com/spring-events
https://iter01.com/605298.html