Skip to content

Commit b825aff

Browse files
committed
fix event bug
1 parent cb501d5 commit b825aff

25 files changed

+288
-37
lines changed

pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
<groupId>com.codingapi.springboot</groupId>
1414
<artifactId>springboot-parent</artifactId>
15-
<version>2.8.10</version>
15+
<version>2.8.11</version>
1616

1717
<url>https://github.com/codingapi/springboot-framewrok</url>
1818
<name>springboot-parent</name>

springboot-starter-data-fast/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<parent>
66
<artifactId>springboot-parent</artifactId>
77
<groupId>com.codingapi.springboot</groupId>
8-
<version>2.8.10</version>
8+
<version>2.8.11</version>
99
</parent>
1010
<modelVersion>4.0.0</modelVersion>
1111

springboot-starter-security/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<parent>
77
<artifactId>springboot-parent</artifactId>
88
<groupId>com.codingapi.springboot</groupId>
9-
<version>2.8.10</version>
9+
<version>2.8.11</version>
1010
</parent>
1111

1212
<artifactId>springboot-starter-security</artifactId>

springboot-starter/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<parent>
66
<groupId>com.codingapi.springboot</groupId>
77
<artifactId>springboot-parent</artifactId>
8-
<version>2.8.10</version>
8+
<version>2.8.11</version>
99
</parent>
1010
<artifactId>springboot-starter</artifactId>
1111

+15-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
package com.codingapi.springboot.framework.handler;
1+
package com.codingapi.springboot.framework.event;
22

3-
import com.codingapi.springboot.framework.event.IEvent;
3+
import com.codingapi.springboot.framework.exception.EventException;
4+
import com.codingapi.springboot.framework.exception.EventLoopException;
45

56
import java.util.ArrayList;
67
import java.util.List;
@@ -42,28 +43,32 @@ public void addHandler(IHandler handler) {
4243

4344
@Override
4445
public void handler(IEvent event) {
46+
Class<?> eventClass = event.getClass();
47+
List<Exception> errorStack = new ArrayList<>();
48+
boolean throwException = false;
4549
for (IHandler<IEvent> handler : handlers) {
4650
try {
47-
Class<?> eventClass = event.getClass();
4851
Class<?> targetClass = handler.getHandlerEventClass();
4952
if (eventClass.equals(targetClass)) {
5053
handler.handler(event);
5154
}
5255
} catch (Exception e) {
53-
Exception error = null;
56+
if (e instanceof EventLoopException) {
57+
throw e;
58+
}
5459
try {
5560
handler.error(e);
61+
errorStack.add(e);
5662
} catch (Exception err) {
57-
error = err;
58-
}
59-
if (error != null) {
60-
throw new RuntimeException(error);
63+
throwException = true;
64+
errorStack.add(err);
6165
}
6266
}
6367
}
68+
if(throwException){
69+
throw new EventException(errorStack);
70+
}
6471
}
6572

6673

67-
68-
6974
}

springboot-starter/src/main/java/com/codingapi/springboot/framework/event/DomainEvent.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,14 @@ public class DomainEvent extends ApplicationEvent {
1818
@Getter
1919
private final boolean sync;
2020

21-
public DomainEvent(Object source, boolean sync) {
21+
@Getter
22+
private final String traceId;
23+
24+
25+
public DomainEvent(Object source, boolean sync, String traceId) {
2226
super(source);
2327
this.event = (IEvent) source;
2428
this.sync = sync;
29+
this.traceId = traceId;
2530
}
26-
2731
}

springboot-starter/src/main/java/com/codingapi/springboot/framework/event/DomainEventContext.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ public static DomainEventContext getInstance() {
2525

2626
private void push(IEvent event, boolean sync) {
2727
if (context != null) {
28-
context.publishEvent(new DomainEvent(event, sync));
28+
String traceId = EventTraceContext.getInstance().getOrCreateTrace();
29+
EventTraceContext.getInstance().addEvent(traceId,event);
30+
context.publishEvent(new DomainEvent(event, sync,traceId));
2931
}
3032
}
3133

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package com.codingapi.springboot.framework.event;
2+
3+
import lombok.Getter;
4+
5+
import java.util.ArrayList;
6+
import java.util.HashMap;
7+
import java.util.List;
8+
import java.util.Map;
9+
10+
/**
11+
* 事件栈上下文
12+
*/
13+
public class EventStackContext {
14+
15+
private final Map<String, List<Class<?>>> eventClassStack = new HashMap<>();
16+
private final Map<String, List<IEvent>> eventStack = new HashMap<>();
17+
18+
@Getter
19+
private final static EventStackContext instance = new EventStackContext();
20+
21+
private EventStackContext() {
22+
23+
}
24+
25+
private void addEventClass(String traceId, IEvent event) {
26+
List<Class<?>> events = eventClassStack.get(traceId);
27+
if (events == null) {
28+
events = new ArrayList<>();
29+
}
30+
events.add(event.getClass());
31+
eventClassStack.put(traceId, events);
32+
}
33+
34+
private void addEventStack(String traceId, IEvent event) {
35+
List<IEvent> events = eventStack.get(traceId);
36+
if (events == null) {
37+
events = new ArrayList<>();
38+
}
39+
events.add(event);
40+
eventStack.put(traceId, events);
41+
}
42+
43+
44+
void addEvent(String traceId, IEvent event) {
45+
addEventClass(traceId, event);
46+
addEventStack(traceId, event);
47+
}
48+
49+
boolean checkEventLoop(String traceId, IEvent event) {
50+
List<Class<?>> events = eventClassStack.get(traceId);
51+
if (events != null) {
52+
return events.contains(event.getClass());
53+
}
54+
return false;
55+
}
56+
57+
public List<IEvent> getEvents(String eventKey) {
58+
if(eventKey!=null) {
59+
String traceId = eventKey.split("#")[0];
60+
return eventStack.get(traceId);
61+
}
62+
return null;
63+
}
64+
65+
public List<Class<?>> getEventClasses(String eventKey) {
66+
if(eventKey!=null) {
67+
String traceId = eventKey.split("#")[0];
68+
return eventClassStack.get(traceId);
69+
}
70+
return null;
71+
}
72+
73+
74+
void remove(String traceId) {
75+
eventStack.remove(traceId);
76+
eventClassStack.remove(traceId);
77+
}
78+
79+
80+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package com.codingapi.springboot.framework.event;
2+
3+
import com.codingapi.springboot.framework.exception.EventLoopException;
4+
import com.codingapi.springboot.framework.utils.RandomGenerator;
5+
import lombok.Getter;
6+
7+
import java.util.*;
8+
9+
/**
10+
* 事件跟踪上下文
11+
*/
12+
public class EventTraceContext {
13+
14+
@Getter
15+
private final static EventTraceContext instance = new EventTraceContext();
16+
17+
// trace key
18+
private final Set<String> traceKeys = new HashSet<>();
19+
20+
// thread local
21+
private final ThreadLocal<String> threadLocal = new ThreadLocal<>();
22+
23+
// event listenerKey state
24+
private final Map<String, Boolean> eventKeyState = new HashMap<>();
25+
26+
27+
private EventTraceContext() {
28+
}
29+
30+
String getOrCreateTrace() {
31+
String eventKey = threadLocal.get();
32+
if (eventKey != null) {
33+
return eventKey.split("#")[0];
34+
}
35+
String traceId = UUID.randomUUID().toString().replaceAll("-", "");
36+
traceKeys.add(traceId);
37+
return traceId;
38+
}
39+
40+
/**
41+
* get event key
42+
* traceId = eventKey.split("#")[0]
43+
*/
44+
public String getEventKey() {
45+
return threadLocal.get();
46+
}
47+
48+
void createEventKey(String traceId) {
49+
String eventKey = traceId + "#" + RandomGenerator.randomString(8);
50+
eventKeyState.put(eventKey, false);
51+
threadLocal.set(eventKey);
52+
}
53+
54+
void checkEventState() {
55+
String eventKey = threadLocal.get();
56+
if (eventKey != null) {
57+
boolean state = eventKeyState.get(eventKey);
58+
if (!state) {
59+
// event execute finish
60+
String traceId = eventKey.split("#")[0];
61+
traceKeys.remove(traceId);
62+
EventStackContext.getInstance().remove(traceId);
63+
}
64+
eventKeyState.remove(eventKey);
65+
}
66+
threadLocal.remove();
67+
}
68+
69+
void addEvent(String traceId, IEvent event) {
70+
boolean hasEventLoop = EventStackContext.getInstance().checkEventLoop(traceId, event);
71+
if (hasEventLoop) {
72+
List<Class<?>> stack = EventStackContext.getInstance().getEventClasses(traceId);
73+
traceKeys.remove(traceId);
74+
EventStackContext.getInstance().remove(traceId);
75+
eventKeyState.remove(traceId);
76+
threadLocal.remove();
77+
throw new EventLoopException(stack, event);
78+
}
79+
EventStackContext.getInstance().addEvent(traceId, event);
80+
}
81+
}

springboot-starter/src/main/java/com/codingapi/springboot/framework/handler/Handler.java renamed to springboot-starter/src/main/java/com/codingapi/springboot/framework/event/Handler.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.codingapi.springboot.framework.handler;
1+
package com.codingapi.springboot.framework.event;
22

33
import java.lang.annotation.*;
44

Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.codingapi.springboot.framework.handler;
1+
package com.codingapi.springboot.framework.event;
22

33
import com.codingapi.springboot.framework.registrar.RegisterBeanScanner;
44
import lombok.SneakyThrows;
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
package com.codingapi.springboot.framework.event;
22

33

4+
import java.io.Serializable;
5+
46
/**
57
* 默认同步事件
68
* <p>
79
* 关于事件与事务之间的关系说明:
810
* 事件本身不应该同步主业务的事务,即事件对于主业务来说,可成功可失败,成功与失败都不应该强关联主体业务。
911
* 若需要让主体业务与分支做事务同步的时候,那不应该采用事件机制,而应该直接采用调用的方式实现业务绑定。
1012
*/
11-
public interface IEvent {
13+
public interface IEvent extends Serializable {
1214

1315

1416
}

springboot-starter/src/main/java/com/codingapi/springboot/framework/handler/IHandler.java renamed to springboot-starter/src/main/java/com/codingapi/springboot/framework/event/IHandler.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
package com.codingapi.springboot.framework.handler;
1+
package com.codingapi.springboot.framework.event;
22

3-
import com.codingapi.springboot.framework.event.IEvent;
43
import org.springframework.core.ResolvableType;
54

65
/**
@@ -19,10 +18,11 @@ public interface IHandler<T extends IEvent> {
1918

2019
/**
2120
* 异常回掉,在多订阅的情况下,为了实现订阅的独立性,将异常的处理放在回掉函数中。
21+
* 当异常抛出以后,会阻止后续的事件执行
2222
*
2323
* @param exception 异常信息
2424
*/
25-
default void error(Exception exception) throws Exception{
25+
default void error(Exception exception) throws Exception {
2626
throw exception;
2727
}
2828

@@ -32,7 +32,7 @@ default void error(Exception exception) throws Exception{
3232
*/
3333
default Class<?> getHandlerEventClass() {
3434
ResolvableType resolvableType = ResolvableType.forClass(getClass()).as(IHandler.class);
35-
return (Class<T>) resolvableType.getGeneric(0).resolve();
35+
return resolvableType.getGeneric(0).resolve();
3636
}
3737

3838

+15-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
package com.codingapi.springboot.framework.handler;
1+
package com.codingapi.springboot.framework.event;
22

3-
import com.codingapi.springboot.framework.event.DomainEvent;
43
import lombok.extern.slf4j.Slf4j;
54
import org.springframework.context.ApplicationListener;
65

@@ -28,11 +27,23 @@ public SpringEventHandler(List<IHandler> handlers) {
2827

2928
@Override
3029
public void onApplicationEvent(DomainEvent domainEvent) {
30+
String traceId = domainEvent.getTraceId();
31+
3132
if (domainEvent.isSync()) {
32-
ApplicationHandlerUtils.getInstance().handler(domainEvent.getEvent());
33+
try {
34+
EventTraceContext.getInstance().createEventKey(traceId);
35+
ApplicationHandlerUtils.getInstance().handler(domainEvent.getEvent());
36+
} finally {
37+
EventTraceContext.getInstance().checkEventState();
38+
}
3339
} else {
3440
executorService.execute(() -> {
35-
ApplicationHandlerUtils.getInstance().handler(domainEvent.getEvent());
41+
try {
42+
EventTraceContext.getInstance().createEventKey(traceId);
43+
ApplicationHandlerUtils.getInstance().handler(domainEvent.getEvent());
44+
} finally {
45+
EventTraceContext.getInstance().checkEventState();
46+
}
3647
});
3748
}
3849
}
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.codingapi.springboot.framework.handler;
1+
package com.codingapi.springboot.framework.event;
22

33
import org.springframework.beans.factory.annotation.Autowired;
44
import org.springframework.context.annotation.Bean;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.codingapi.springboot.framework.exception;
2+
3+
import lombok.Getter;
4+
5+
import java.util.List;
6+
import java.util.stream.Collectors;
7+
8+
@Getter
9+
public class EventException extends RuntimeException {
10+
11+
private final List<Exception> error;
12+
13+
public EventException(List<Exception> error) {
14+
super(error.stream().map(Exception::getMessage).collect(Collectors.joining("\n")));
15+
this.error = error;
16+
}
17+
}

0 commit comments

Comments
 (0)