場景說明:在使用SpringBoot時,總是要添加一大堆自定義事件,實現ApplicationEvent,來實現事件發送。
這樣寫代碼量非常大。為了方便和避免出錯,封裝自定義的模塊,快速實現泛型中調用SpringEvent實現事件。省去配置,簡化代碼,增加多線程并發處理。
一、配置自定義注解和泛型事件
1、添加自定義注解來開啟配置
import org.springframework.context.annotation.Import;import java.lang.annotation.*;/*** 自動啟用 Spring Event事件*/ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Import({QySpringEventConfiguration.class}) @Documented public @interface EnableQySpringEvent { }
2、自定義配置中,設置線程池和注入配置
import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.SimpleApplicationEventMulticaster; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.core.task.TaskExecutor; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;/*** 配置,加載EventBus事件總線*/ @Configuration @EnableAsync // 自動開啟異步處理 @Slf4j public class QySpringEventConfiguration {private final ApplicationContext applicationContext;@Autowiredpublic QySpringEventConfiguration(ApplicationContext applicationContext) {this.applicationContext = applicationContext;}@Beanpublic QyEventService qySpringEventService() {log.info("<<<<<<<<<<<<<<< 注入QyEventService實現自定義事件 >>>>>>>>>>>>>>>>>>");return new QySpringEventServiceImpl(applicationContext);}/*** 指定線程池,專用于事件訂閱和發布** @return*/@Bean(name = "eventTaskExecutor")public TaskExecutor eventTaskExecutor() {ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();taskExecutor.setThreadNamePrefix("qy-springEventTaskExecutor-");taskExecutor.setCorePoolSize(5);taskExecutor.setQueueCapacity(100);taskExecutor.setMaxPoolSize(5);taskExecutor.initialize();return taskExecutor;}/*** 為SpringEvent指定線程池* 注意beanName必須為applicationEventMulticaster;下面的源碼中你將看到** @param beanFactory* @return*/@Bean(name = AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME)public SimpleApplicationEventMulticaster eventMulticaster(BeanFactory beanFactory) {SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);eventMulticaster.setTaskExecutor(eventTaskExecutor());return eventMulticaster;}}
3、定義支持泛型的事件,省去每次配置ApplicationEvent的過程
import lombok.Getter; import lombok.Setter; import org.springframework.context.ApplicationEvent; import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableTypeProvider;/*** 帶泛型的多重使用器** @param <T>*/ @Setter @Getter public class QyEvent<T> extends ApplicationEvent implements ResolvableTypeProvider {private T data;public QyEvent(T data) {super(data);this.data = data;}public QyEvent(Object source, T data) {super(source);this.data = data;}@Overridepublic ResolvableType getResolvableType() {return ResolvableType.forClassWithGenerics(getClass(), ResolvableType.forInstance(data));} }
4、定義發送服務
/*** Spring內部自帶的事件發布器*/ public interface QyEventService {/*** 發布事件** @param qyEvent*/<T> void publishEvent(QyEvent<T> qyEvent);}
5、服務實現類
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component;@Component public class QySpringEventServiceImpl implements QyEventService {private final ApplicationContext applicationContext;@Autowiredpublic QySpringEventServiceImpl(ApplicationContext applicationContext) {this.applicationContext = applicationContext;}@Overridepublic <T> void publishEvent(QyEvent<T> qyEvent) {applicationContext.publishEvent(qyEvent);} }
更多精彩內容關注我的公眾號:青塬科技。
二、在使用時
1、在入口處添加注解
@EnableQySpringEvent
2、使用時,在服務中添加
@Resource
QyEventService qyEventService;
測試發送消息內容:
IntStream.rangeClosed(0, 10).forEach(item -> {qyEventService.publishEvent(new QyEvent<>("test" + item)); });
3、添加監聽器
import lombok.extern.slf4j.Slf4j; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component;/*** 事件監聽處理器*/ @Component @Slf4j public class QyEventListener {@Async // 異步實現@EventListener // 監聽器,會自動識別類型public void onOperationLogEvent(QyEvent<String> event) {log.info("QyEvent Listener recieve message: " + event.getData());} }
日志顯示:
2024-05-21 14:51:22.798 INFO 14757 --- [qy-springEventTaskExecutor-1] c.q.justtest.listener.QyEventListener : QyEvent Listener recieve message: test5 2024-05-21 14:51:22.798 INFO 14757 --- [qy-springEventTaskExecutor-3] c.q.justtest.listener.QyEventListener : QyEvent Listener recieve message: test3 2024-05-21 14:51:22.798 INFO 14757 --- [qy-springEventTaskExecutor-2] c.q.justtest.listener.QyEventListener : QyEvent Listener recieve message: test4 2024-05-21 14:51:22.798 INFO 14757 --- [qy-springEventTaskExecutor-4] c.q.justtest.listener.QyEventListener : QyEvent Listener recieve message: test6 2024-05-21 14:51:22.798 INFO 14757 --- [qy-springEventTaskExecutor-1] c.q.justtest.listener.QyEventListener : QyEvent Listener recieve message: test7 2024-05-21 14:51:22.798 INFO 14757 --- [qy-springEventTaskExecutor-4] c.q.justtest.listener.QyEventListener : QyEvent Listener recieve message: test1 2024-05-21 14:51:22.798 INFO 14757 --- [qy-springEventTaskExecutor-4] c.q.justtest.listener.QyEventListener : QyEvent Listener recieve message: test8 2024-05-21 14:51:22.798 INFO 14757 --- [qy-springEventTaskExecutor-1] c.q.justtest.listener.QyEventListener : QyEvent Listener recieve message: test9 2024-05-21 14:51:22.798 INFO 14757 --- [qy-springEventTaskExecutor-4] c.q.justtest.listener.QyEventListener : QyEvent Listener recieve message: test2 2024-05-21 14:51:22.798 INFO 14757 --- [qy-springEventTaskExecutor-2] c.q.justtest.listener.QyEventListener : QyEvent Listener recieve message: test0 2024-05-21 14:51:22.798 INFO 14757 --- [qy-springEventTaskExecutor-3] c.q.justtest.listener.QyEventListener : QyEvent Listener recieve message: test10
可以發現已經實現多線程,并且并發打印出消息。
總結
關于多線程的內容已經說完了,但是我還想說點別的,主要想說一下我們應該學習哪些技術才能讓它更加保值。
在我看來,越偏向于業務的技術越不容易過時,為什么呢?需求在變,技術一直在變,業務也一直在迭代。前端技術的發展非常快,也涌現出很多的框架(例如 HTML4 到 HTML5 的升級,或者從jQuery 到前端三大框架的轉變),但是總歸就是兩個字:效率。
作為開發者,我們需要保持好奇心和學習熱情,不斷探索新的技術,只有這樣,我們才能在這個快速發展的時代中立于不敗之地。介紹一款程序員都應該知道的軟件JNPF快速開發平臺,很多人都嘗試用過它,它是功能的集大成者,任何信息化系統都可以基于它開發出來。
JNPF可以實現應用從創建、配置、開發、測試到發布、運維、升級等完整生命周期的管理。減少了傳統應用程序的代碼編寫量,通過圖形化、可視化的界面,以拖放組件的方式,即可快速生成應用程序的產品,大幅降低了開發企業管理類軟件的難度。
當然,我更建議大家成為一個全棧,不要把自己的定位局限于前端。