特殊事件PayloadApplicationEvent
Spring容器中除了提供有ApplicationEvent类型事件之外,还有提供一种叫做
PayloadApplicationEvent的事件类型(也是实现了ApplicationEvent接口)
网络异常,图片无法展示
|
这类事件设计的主要目的在于,发布事件的时候不一定需要定义一个Event对象,可以是直接发送字符串等类型。
使用案例:
package org.idea.spring.framework.event; import org.springframework.context.*; import org.springframework.context.annotation.AnnotationConfigApplicationContext; /** * @Author linhao * @Date created in 10:14 下午 2021/5/29 */ public class PayLoadEventDemo2 implements ApplicationEventPublisherAware { public ApplicationEventPublisher applicationEventPublisher; public static void main(String[] args) { AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(); annotationConfigApplicationContext.register(PayLoadEventDemo2.class); annotationConfigApplicationContext.register(MyPayloadApplicationEventListener.class); annotationConfigApplicationContext.refresh(); PayLoadEventDemo2 payLoadEventDemo = annotationConfigApplicationContext.getBean(PayLoadEventDemo2.class); payLoadEventDemo.applicationEventPublisher.publishEvent("hello"); payLoadEventDemo.applicationEventPublisher.publishEvent(new MyPayloadApplicationEvent<String>(payLoadEventDemo,"payload")); annotationConfigApplicationContext.close(); } @Override public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { this.applicationEventPublisher = applicationEventPublisher; } /** * 可以接收payload事件? */ static class MyPayloadApplicationEventListener implements ApplicationListener<MyPayloadApplicationEvent>{ @Override public void onApplicationEvent(MyPayloadApplicationEvent myPayloadApplicationEvent) { System.out.println("[MyPayloadApplicationEventListener] 接收到:%s,"+myPayloadApplicationEvent); } } static class MyPayloadApplicationEvent<String> extends PayloadApplicationEvent<String> { /** * Create a new PayloadApplicationEvent. * * @param source the object on which the event initially occurred (never {@code null}) * @param payload the payload object (never {@code null}) */ public MyPayloadApplicationEvent(Object source, String payload) { super(source, payload); } } } 复制代码
这段程序实际上个人感觉是有bug的,因为自己发送的payload事件并没有在监听器中收到消息。
网络异常,图片无法展示
|
后来在Spring内部源代码中的注释说明中跟多是提供给内部框架锁使用的,但是单从SpringFramework 5.2.3版本中的源代码看来,自己并没有看到太多的使用场景。而且关于PayLoad事件在使用过程中感觉源代码中对于事件类型的兼容性也不是太友善,所以不是太推荐使用。
(注意:使用@EventListener的时候,无法监听到PayLoad事件的发送)
事件内部的taskExecutor有何用处
在前边我们提到了可以基于注解的方式来实现异步线程的效果,但是注解的方式更多地是基于方法级别的粒度效果,如果希望实现全局性的事件处理异步化可以重构多播器中的线程池参数:
案例代码:首先需要定义多个Listener
package org.idea.spring.framework.event.multiEvent.listener; import lombok.SneakyThrows; import org.idea.spring.framework.event.multiEvent.events.MyAsyncEvent; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; /** * @Author linhao * @Date created in 3:22 下午 2021/5/30 */ @Component public class Listener3 implements ApplicationListener<MyAsyncEvent> { @SneakyThrows @Override public void onApplicationEvent(MyAsyncEvent event) { System.out.println("3---" + event.getSource() + "thread is " + Thread.currentThread().getName()); Thread.sleep(1000); System.out.println("end 3"); } } package org.idea.spring.framework.event.multiEvent.listener; import lombok.SneakyThrows; import org.idea.spring.framework.event.multiEvent.events.MyAsyncEvent; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; /** * @Author linhao * @Date created in 3:22 下午 2021/5/30 */ @Component public class Listener2 implements ApplicationListener<MyAsyncEvent> { @SneakyThrows @Override public void onApplicationEvent(MyAsyncEvent event) { System.out.println("2---" + event.getSource() + "thread is " + Thread.currentThread().getName()); Thread.sleep(1000); System.out.println("end 2"); } } package org.idea.spring.framework.event.multiEvent.listener; import lombok.SneakyThrows; import org.idea.spring.framework.event.multiEvent.events.MyAsyncEvent; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; /** * @Author linhao * @Date created in 3:22 下午 2021/5/30 */ @Component public class Listener1 implements ApplicationListener<MyAsyncEvent> { @SneakyThrows @Override public void onApplicationEvent(MyAsyncEvent event) { System.out.println("1---" + event.getSource() + "thread is " + Thread.currentThread().getName()); Thread.sleep(1000); System.out.println("end 1"); } } 复制代码
一个自定义的Spring事件
package org.idea.spring.framework.event.multiEvent.events; import org.springframework.context.ApplicationEvent; /** * @Author linhao * @Date created in 3:14 下午 2021/5/30 */ public class MyAsyncEvent extends ApplicationEvent { /** * Create a new {@code ApplicationEvent}. * * @param source the object on which the event initially occurred or with * which the event is associated (never {@code null}) */ public MyAsyncEvent(Object source) { super(source); } } 复制代码
一个配置全局性事件异步处理的config,这个配置生效之后,我们就不需要在每个事件接收端都配置@Async注解了
package org.idea.spring.framework.event.multiEvent.events; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationListener; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.*; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.scheduling.concurrent.CustomizableThreadFactory; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 重写全局性事件异步发送组件 * * @Author linhao * @Date created in 3:29 下午 2021/5/30 */ @Configuration public class MyEventPublishConfig implements ApplicationListener<ContextRefreshedEvent> { @Override public void onApplicationEvent(ContextRefreshedEvent event) { ApplicationContext applicationContext = event.getApplicationContext(); ApplicationEventMulticaster applicationEventMulticaster = applicationContext.getBean(AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class); SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = (SimpleApplicationEventMulticaster) applicationEventMulticaster; ExecutorService taskExecutor = Executors.newFixedThreadPool(10,new CustomizableThreadFactory("pool-idea-")); simpleApplicationEventMulticaster.setTaskExecutor(taskExecutor); simpleApplicationEventMulticaster.addApplicationListener(new ApplicationListener<ContextClosedEvent>() { @Override public void onApplicationEvent(ContextClosedEvent event) { if (!taskExecutor.isShutdown()) { taskExecutor.shutdown(); System.out.println("shutdown"); } } }); } } 复制代码
最后是测试的service
@Service public class EventTestService { @Autowired private ApplicationEventPublisher applicationEventPublisher; public void doSendMsg(){ System.out.println(" ===== send ===== "); applicationEventPublisher.publishEvent(new MyAsyncEvent("this is async")); } } package org.idea.spring.framework.event.multiEvent; import org.idea.spring.framework.event.multiEvent.service.EventTestService; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import javax.annotation.Resource; /** * * * @Author linhao * @Date created in 3:13 下午 2021/5/30 */ @SpringBootApplication public class SpringApplicaitonDemo implements CommandLineRunner { @Resource private EventTestService eventTestService; public static void main(String[] args) { SpringApplication.run(SpringApplicaitonDemo.class); } @Override public void run(String... args) throws Exception { Thread.sleep(1000); eventTestService.doSendMsg(); } } 复制代码
这样的全局性配置虽然能够减少我们在实际编码过程中异步化操作的繁琐步骤,但是针对的粒度也比较高。所以在实际运用的时候需要结合实际业务场景使用。