Skip to content

Commit a21748c

Browse files
authored
docs: add shared events document for developer (#468)
### What this PR does? 添加共享事件文档 ```release-note None ```
1 parent adc8202 commit a21748c

File tree

4 files changed

+315
-1
lines changed

4 files changed

+315
-1
lines changed
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
---
2+
title: 事件共享
3+
description: 介绍 Halo 与插件以及插件与插件之间的事件共享机制。
4+
---
5+
6+
在 Halo 插件开发中,事件机制是实现插件间通信和功能解耦的重要工具。
7+
`@SharedEvent` 注解使得插件可以方便地在 Halo 主程序和其他插件间共享自定义的事件。
8+
当插件为自定义的 Spring Event 类型标注 `@SharedEvent` 注解时,Halo 将自动将该事件共享到事件总线,其他依赖了此插件的组件即可订阅并监听该事件。
9+
通过这一机制,插件不仅可以监听 Halo 提供的共享事件,也可以发布自己的共享事件,从而实现插件与插件之间的事件通信机制。
10+
11+
## 监听 Halo 提供的共享事件
12+
13+
Halo 提供了一些内置共享事件,插件开发者可以利用这些事件响应系统中的特定行为。以下步骤说明如何在插件中监听这些事件。
14+
15+
### 注册监听器
16+
17+
在插件中,要监听 Halo 提供的共享事件,首先需要注册事件监听器。事件监听器通常通过 `@EventListener` 注解来注册。
18+
19+
Halo 在检测到事件触发时会调用被标注的监听方法。
20+
21+
```java
22+
import org.springframework.context.event.EventListener;
23+
import org.springframework.stereotype.Component;
24+
import run.halo.app.event.SomeSharedEvent;
25+
26+
@Component
27+
public class HaloEventListener {
28+
29+
@EventListener
30+
public void handleSomeSharedEvent(SomeSharedEvent event) {
31+
// 处理事件的逻辑
32+
System.out.println("Received shared event: " + event.getMessage());
33+
}
34+
}
35+
```
36+
37+
在上面的示例中,handleSomeSharedEvent 方法被注册为 SomeSharedEvent 的监听器。
38+
当 SomeSharedEvent 事件触发时,Halo 将自动调用此方法并传入事件实例,开发者可以在该方法中编写业务逻辑来响应事件。
39+
40+
当然也可以通过实现 `org.springframework.context.ApplicationListener` 接口来监听,这与 [Spring 事件监听](https://docs.spring.io/spring-framework/reference/core/beans/context-introduction.html#context-functionality-events) 的方式一致。
41+
42+
### Halo 内置共享事件
43+
44+
#### 文章
45+
46+
- PostPublishedEvent:文章被发布
47+
- PostUnpublishedEvent:文章被取消发布
48+
- PostUpdatedEvent:文章被更新
49+
- PostDeletedEvent:文章被删除
50+
- PostVisibleChangedEvent:文章的可见性(spec.visible)被修改
51+
52+
#### 第三方登陆
53+
54+
- UserConnectionDisconnectedEvent:用户解绑第三方登陆方式时触发的事件
55+
56+
## 发布自定义共享事件
57+
58+
除了监听已有的共享事件,插件也可以定义和发布自定义的共享事件,使得其他依赖该插件的组件能够监听和响应。
59+
60+
### 定义共享事件类型
61+
62+
要定义一个共享事件,首先需要创建一个事件类,并使用 `@SharedEvent` 注解对其进行标注。通常这个类需要继承自 Spring 的 ApplicationEvent 类或其他类似的事件基类。
63+
64+
示例代码:
65+
66+
```java
67+
import run.halo.app.plugin.SharedEvent;
68+
import org.springframework.context.ApplicationEvent;
69+
70+
@SharedEvent
71+
public class CustomSharedEvent extends ApplicationEvent {
72+
73+
private final String message;
74+
75+
public CustomSharedEvent(Object source, String message) {
76+
super(source);
77+
this.message = message;
78+
}
79+
80+
public String getMessage() {
81+
return message;
82+
}
83+
}
84+
```
85+
86+
在上面的例子中,CustomSharedEvent 是一个自定义的共享事件,带有 message 属性,用于传递信息。
87+
88+
### 发布共享事件到事件总线
89+
90+
要发布事件,可以通过 Spring 的 `ApplicationEventPublisher` 发布自定义事件到事件总线,从而触发其他插件的监听器。
91+
92+
示例代码:
93+
94+
```java
95+
import org.springframework.beans.factory.annotation.Autowired;
96+
import org.springframework.context.ApplicationEventPublisher;
97+
import org.springframework.stereotype.Component;
98+
99+
@Component
100+
public class CustomEventPublisher {
101+
102+
@Autowired
103+
private ApplicationEventPublisher eventPublisher;
104+
105+
public void publishCustomEvent(String message) {
106+
CustomSharedEvent event = new CustomSharedEvent(this, message);
107+
eventPublisher.publishEvent(event);
108+
System.out.println("Published custom shared event with message: " + message);
109+
}
110+
}
111+
```
112+
113+
在这里,`publishCustomEvent` 方法会创建一个 CustomSharedEvent 实例并将其发布到事件总线。任何依赖此事件提供者插件的插件监听 CustomSharedEvent 都将收到该事件并响应。
114+
115+
这需要以下步骤作为前提:
116+
117+
1. 插件 A 将包含了 `CustomSharedEvent` 这个类的依赖 `plugin-a-api` 发布到 Maven 仓库
118+
2. 插件 B 引入 `plugin-a-api` 作为项目依赖并将其作为 `compileOnly`,必须是 `compileOnly` 依赖
119+
120+
```gradle
121+
dependencies {
122+
compileOnly "run.halo.example:plugin-a-api:1.0.0"
123+
}
124+
```
125+
126+
3. 配置插件 B 的 `plugin.yaml` 中的 `pluginDependencies` 依赖插件 A,参考 [插件依赖声明](dependency.md#依赖声明方式)
127+
128+
:::info
129+
关于为什么必须将插件 A 的 `plugin-a-api` 声明为 `compileOnly`?
130+
131+
插件类加载的顺序是:
132+
133+
先从当前插件找 -> 不存在则从 Halo 找 -> 不存在则从依赖插件找。
134+
135+
插件 B 要监听到插件 A 的事件,必须确保是同一个类型也就是同一个类加载器加载的类。
136+
那么只有声明为 compileOnly,插件 B 监听事件时才能从依赖的插件 A 中查找已加载的类
137+
:::
138+
139+
## 最佳实践
140+
141+
- 事件命名与分类:使用清晰且具有描述性的事件名称,避免让使用者产生困惑如 MomentCreatedEvent 不应该在 Moment 创建之前触发因为事件名称表示是创建后的事件。
142+
- 避免冲突与重复订阅:确保事件逻辑集中处理,防止监听器重复触发导致性能问题。
143+
- 性能与资源管理:避免频繁触发事件或长时间占用资源的事件处理逻辑,以确保系统稳定性。
144+
- 异步监听:监听事件时应该尽可能的使用 `@Async` 注解让 Listener 的处理逻辑是异步的,避免阻塞其他监听器处理
145+
146+
```java
147+
import org.springframework.scheduling.annotation.Async;
148+
149+
@Async
150+
@EventListener
151+
public void handleCustomSharedEvent(CustomSharedEvent event) {
152+
// do something...
153+
}
154+
```
155+
156+
- 只发布自己定义的**共享事件**:插件应该始终只去发布自己定义的共享事件避免出现循环,如插件 A 定义的 CustomSharedEvent 只应该由插件 A 去发布,插件 B 中不应该去发布 CustomSharedEvent 事件。

sidebars.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ module.exports = {
298298
},
299299
items: [
300300
"developer-guide/plugin/interaction/dependency",
301+
"developer-guide/plugin/interaction/shared-events",
301302
]
302303
},
303304
{
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
---
2+
title: 事件共享
3+
description: 介绍 Halo 与插件以及插件与插件之间的事件共享机制。
4+
---
5+
6+
在 Halo 插件开发中,事件机制是实现插件间通信和功能解耦的重要工具。
7+
`@SharedEvent` 注解使得插件可以方便地在 Halo 主程序和其他插件间共享自定义的事件。
8+
当插件为自定义的 Spring Event 类型标注 `@SharedEvent` 注解时,Halo 将自动将该事件共享到事件总线,其他依赖了此插件的组件即可订阅并监听该事件。
9+
通过这一机制,插件不仅可以监听 Halo 提供的共享事件,也可以发布自己的共享事件,从而实现插件与插件之间的事件通信机制。
10+
11+
## 监听 Halo 提供的共享事件
12+
13+
Halo 提供了一些内置共享事件,插件开发者可以利用这些事件响应系统中的特定行为。以下步骤说明如何在插件中监听这些事件。
14+
15+
### 注册监听器
16+
17+
在插件中,要监听 Halo 提供的共享事件,首先需要注册事件监听器。事件监听器通常通过 `@EventListener` 注解来注册。
18+
19+
Halo 在检测到事件触发时会调用被标注的监听方法。
20+
21+
```java
22+
import org.springframework.context.event.EventListener;
23+
import org.springframework.stereotype.Component;
24+
import run.halo.app.event.SomeSharedEvent;
25+
26+
@Component
27+
public class HaloEventListener {
28+
29+
@EventListener
30+
public void handleSomeSharedEvent(SomeSharedEvent event) {
31+
// 处理事件的逻辑
32+
System.out.println("Received shared event: " + event.getMessage());
33+
}
34+
}
35+
```
36+
37+
在上面的示例中,handleSomeSharedEvent 方法被注册为 SomeSharedEvent 的监听器。
38+
当 SomeSharedEvent 事件触发时,Halo 将自动调用此方法并传入事件实例,开发者可以在该方法中编写业务逻辑来响应事件。
39+
40+
当然也可以通过实现 `org.springframework.context.ApplicationListener` 接口来监听,这与 [Spring 事件监听](https://docs.spring.io/spring-framework/reference/core/beans/context-introduction.html#context-functionality-events) 的方式一致。
41+
42+
### Halo 内置共享事件
43+
44+
#### 文章
45+
46+
- PostPublishedEvent:文章被发布
47+
- PostUnpublishedEvent:文章被取消发布
48+
- PostUpdatedEvent:文章被更新
49+
- PostDeletedEvent:文章被删除
50+
- PostVisibleChangedEvent:文章的可见性(spec.visible)被修改
51+
52+
#### 第三方登陆
53+
54+
- UserConnectionDisconnectedEvent:用户解绑第三方登陆方式时触发的事件
55+
56+
## 发布自定义共享事件
57+
58+
除了监听已有的共享事件,插件也可以定义和发布自定义的共享事件,使得其他依赖该插件的组件能够监听和响应。
59+
60+
### 定义共享事件类型
61+
62+
要定义一个共享事件,首先需要创建一个事件类,并使用 `@SharedEvent` 注解对其进行标注。通常这个类需要继承自 Spring 的 ApplicationEvent 类或其他类似的事件基类。
63+
64+
示例代码:
65+
66+
```java
67+
import run.halo.app.plugin.SharedEvent;
68+
import org.springframework.context.ApplicationEvent;
69+
70+
@SharedEvent
71+
public class CustomSharedEvent extends ApplicationEvent {
72+
73+
private final String message;
74+
75+
public CustomSharedEvent(Object source, String message) {
76+
super(source);
77+
this.message = message;
78+
}
79+
80+
public String getMessage() {
81+
return message;
82+
}
83+
}
84+
```
85+
86+
在上面的例子中,CustomSharedEvent 是一个自定义的共享事件,带有 message 属性,用于传递信息。
87+
88+
### 发布共享事件到事件总线
89+
90+
要发布事件,可以通过 Spring 的 `ApplicationEventPublisher` 发布自定义事件到事件总线,从而触发其他插件的监听器。
91+
92+
示例代码:
93+
94+
```java
95+
import org.springframework.beans.factory.annotation.Autowired;
96+
import org.springframework.context.ApplicationEventPublisher;
97+
import org.springframework.stereotype.Component;
98+
99+
@Component
100+
public class CustomEventPublisher {
101+
102+
@Autowired
103+
private ApplicationEventPublisher eventPublisher;
104+
105+
public void publishCustomEvent(String message) {
106+
CustomSharedEvent event = new CustomSharedEvent(this, message);
107+
eventPublisher.publishEvent(event);
108+
System.out.println("Published custom shared event with message: " + message);
109+
}
110+
}
111+
```
112+
113+
在这里,`publishCustomEvent` 方法会创建一个 CustomSharedEvent 实例并将其发布到事件总线。任何依赖此事件提供者插件的插件监听 CustomSharedEvent 都将收到该事件并响应。
114+
115+
这需要以下步骤作为前提:
116+
117+
1. 插件 A 将包含了 `CustomSharedEvent` 这个类的依赖 `plugin-a-api` 发布到 Maven 仓库
118+
2. 插件 B 引入 `plugin-a-api` 作为项目依赖并将其作为 `compileOnly`,必须是 `compileOnly` 依赖
119+
120+
```gradle
121+
dependencies {
122+
compileOnly "run.halo.example:plugin-a-api:1.0.0"
123+
}
124+
```
125+
126+
3. 配置插件 B 的 `plugin.yaml` 中的 `pluginDependencies` 依赖插件 A,参考 [插件依赖声明](dependency.md#依赖声明方式)
127+
128+
:::info
129+
关于为什么必须将插件 A 的 `plugin-a-api` 声明为 `compileOnly`?
130+
131+
插件类加载的顺序是:
132+
133+
先从当前插件找 -> 不存在则从 Halo 找 -> 不存在则从依赖插件找。
134+
135+
插件 B 要监听到插件 A 的事件,必须确保是同一个类型也就是同一个类加载器加载的类。
136+
那么只有声明为 compileOnly,插件 B 监听事件时才能从依赖的插件 A 中查找已加载的类
137+
:::
138+
139+
## 最佳实践
140+
141+
- 事件命名与分类:使用清晰且具有描述性的事件名称,避免让使用者产生困惑如 MomentCreatedEvent 不应该在 Moment 创建之前触发因为事件名称表示是创建后的事件。
142+
- 避免冲突与重复订阅:确保事件逻辑集中处理,防止监听器重复触发导致性能问题。
143+
- 性能与资源管理:避免频繁触发事件或长时间占用资源的事件处理逻辑,以确保系统稳定性。
144+
- 异步监听:监听事件时应该尽可能的使用 `@Async` 注解让 Listener 的处理逻辑是异步的,避免阻塞其他监听器处理
145+
146+
```java
147+
import org.springframework.scheduling.annotation.Async;
148+
149+
@Async
150+
@EventListener
151+
public void handleCustomSharedEvent(CustomSharedEvent event) {
152+
// do something...
153+
}
154+
```
155+
156+
- 只发布自己定义的**共享事件**:插件应该始终只去发布自己定义的共享事件避免出现循环,如插件 A 定义的 CustomSharedEvent 只应该由插件 A 去发布,插件 B 中不应该去发布 CustomSharedEvent 事件。

versioned_sidebars/version-2.20-sidebars.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,8 @@
280280
"id": "developer-guide/plugin/interaction/dependency"
281281
},
282282
"items": [
283-
"developer-guide/plugin/interaction/dependency"
283+
"developer-guide/plugin/interaction/dependency",
284+
"developer-guide/plugin/interaction/shared-events"
284285
]
285286
},
286287
{

0 commit comments

Comments
 (0)