spring事件发布,广播,监听

注:以下代码来自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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值