注:以下代码来自spirng5
事件监听接口 ApplicationEventListener<E extends ApplicationEvent>
该接口只监听ApplicationEvent及其子事件
事件定义抽象类 ApplicationEvent extends EventObject
我们可以自定义各种类型的事件,继承ApplicationEvent
// source参数意在指明该事件的创建者,或提供一些其他信息,但实际上没什么用,看个人需求可随意赋值
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
public class BaseEvent extends ApplicationEvent {
public String msg;
public BaseEvent(String msg) {
super(0);
this.msg = msg;
}
}
事件发布接口 ApplicationEventPublisher
default void publishEvent(ApplicationEvent event) {
publishEvent((Object) event);
}
void publishEvent(Object event);
注:Spring5之前只支持发布ApplicationEvent类型的事件,Spring5之后可以发布任意类型事件,具有更大的扩展性
参考文章:https://www.jianshu.com/p/dcbe8f0afbdb
ApplicationContext接口实现了ApplicationEventPublisher
抽象类AbstractApplicationContext实现了ApplicationContext,实现了publishEvent方法,核心代码如下:
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
// Decorate event as an ApplicationEvent if necessary
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
// 这里即spring5之后,发布非ApplicationEvent事件会被包装成PayloadApplicationEvent事件
else {
applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
}
// Multicast right now if possible - or lazily once the multicaster is initialized
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
// 核心代码
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// ...
}
@Nullable
private ApplicationEventMulticaster applicationEventMulticaster;
// 该方法在容器初始化过程中被调用
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 先找是否存在名为applicationEventMulticaster的ApplicationEventMulticaster对象
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
// 不存在则使用默认的SimpleApplicationEventMulticaster
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException {
if (this.applicationEventMulticaster == null) {
throw new IllegalStateException("ApplicationEventMulticaster not initialized - " +
"call 'refresh' before multicasting events via the context: " + this);
}
return this.applicationEventMulticaster;
}
再看一下SimpleApplicationEventMulticaster事件广播是如何处理的,核心方法:
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
// spring创建的默认实例是未指定executor的,所以会串行调用事件监听者的处理逻辑
else {
invokeListener(listener, event);
}
}
}
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
// 最好同时指定异常处理器
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
// 如果未指定errorHandler的话,无法有效捕捉异常,并上抛异常
else {
doInvokeListener(listener, event);
}
}
@SuppressWarnings({"rawtypes", "unchecked"})
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass()) ||
(event instanceof PayloadApplicationEvent &&
matchesClassCastMessage(msg, ((PayloadApplicationEvent) event).getPayload().getClass()))) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception.
Log loggerToUse = this.lazyLogger;
if (loggerToUse == null) {
loggerToUse = LogFactory.getLog(getClass());
this.lazyLogger = loggerToUse;
}
if (loggerToUse.isTraceEnabled()) {
loggerToUse.trace("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
很显然,串行执行,很不利于业务解耦,遇到耗时长的事件处理逻辑时,会阻塞事件抛出线程。
另外,异常捕获并设计处理逻辑也是非常有必要的
PayloadApplicationEvent
// 携带任意有效负载的ApplicationEvent
public class PayloadApplicationEvent<T> extends ApplicationEvent implements ResolvableTypeProvider {
private final T payload;
// ...
}
发布的事件类型是不是ApplicationEvent类型,类型是B
这种情况下,最终事件会被包装成PayloadApplicationEvent<B>, 那么所有监听者方法onApplicationEvent的参数是PayloadApplicationEvent<B>的监听者会收到此事件。
假设有C是B的父类,且有一个监听者X监听PayloadApplicationEvent<C>,那X是收不到PayloadApplicationEvent<B>类型的事件的
@SpringBootApplication
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
EventUtil.publish(new Mika(1, "mika"));
}
}
public class Mika {
public int age;
public String name;
public Mika(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "Mika{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
@Component
public class ApplicationEventListener3 implements ApplicationListener<PayloadApplicationEvent> {
@Override
public void onApplicationEvent(PayloadApplicationEvent event) {
System.err.println(event.getPayload());
}
}
输出结果:Mika{age=1, name=‘mika’}
自定义事件发布者
我们可以实现ApplicationEventPublisherAware接口来自定义事件发布者,但是于我而言非常麻烦,且无甚必要,了解即可
@Component
public class SaySomethingPublisher implements ApplicationEventPublisherAware{
private ApplicationEventPublisher applicationEventPublisher;
@Autowired("myApplicationEventPublisher")
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
// 调用此方法即
public void saySomething(String msg){
applicationEventPublisher.publishEvent(msg);
}
}
public class MyApplicationEventPublisher implements ApplicationEventPublisher{
@Override
public void publishEvent(Object event) {
System.err.println("自定义发布事件逻辑,非常麻烦嘞");
}
}
自定义事件广播机制
前面说到的SimpleApplicationEventMulticaster在配置了线程池时,就会异步调用事件处理逻辑。但是,对于某些事件,我们并不希望它异步,需要它同步执行,而其他事件仍然保持异步执行。那么此时就需要自定义事件广播机制了。
public class MySimpleApplicationEventMulticaster extends SimpleApplicationEventMulticaster {
private static Logger log = LoggerFactory.getLogger(MySimpleApplicationEventMulticaster.class);
@SuppressWarnings("unchecked")
// ....根据实际业务逻辑编码,这里只提供一个可行思路
public void multicastEvent(final ApplicationEvent event) {
// 默认异步
EventTypeEnum defaultEventType = EventTypeEnum.ASYNC;
for (final ApplicationListener listener : getApplicationListeners(event)) {
try {
Class listenerClass = Class.forName(listener.getClass().getName());
if(listenerClass!=null){
Method onApplicationEventMethod = listenerClass.getMethod("onApplicationEvent",ApplicationEvent.class);
// EventType是自定义的一个简单注解,标注在onApplicationEvent方法上,用来表示该方法应该异步还是同步执行
if(onApplicationEventMethod.isAnnotationPresent(EventType.class)){
//获取该元素上指定类型的注解
EventType eventMethodAnnotation = onApplicationEventMethod.getAnnotation(EventType.class);
defaultEventType = eventMethodAnnotation.value();
}
}
Executor executor = getTaskExecutor();
if (executor != null&&defaultEventType==EventTypeEnum.ASYNC) {
executor.execute(new Runnable() {
public void run() {
listener.onApplicationEvent(event);
}
});
}else {
listener.onApplicationEvent(event);
}
} catch (Exception e) {
log.error("获取监听类实例出错:{},event:{}",e.getMessage(), event);
}
}
}
其实,事件机制除了spring自带的之外,还有google eventbus等框架可以使用。参考https://blog.csdn.net/java_lifeng/article/details/120263631