spring事件驱动编程--demo

引用: https://juejin.im/post/5d93fa78f265da5b991d5133

谈到Spring 事件驱动模型,我想大家都不陌生,事件驱动模型,通常也可以说是观察者设计模式。
java本身也自带了对事件驱动的支持,但是大部分都是用于我们的客户端开发,比如GUI ,Swing这些,而Spring 则在java的基础上,扩展了对事件驱动的支持。

废话不多说,直接撸代码。

事件驱动编程

自定义ApplicationEvent

我们新建一个类NotifyEvent 继承ApplicationEvent,用于封装我们事件额外的信息,这里则是String类型的msg,用于记录详细的事件内容。

public class NotifyEvent extends ApplicationEvent {

    @Getter
    private String msg;
    
    public NotifyEvent(Object source, String msg) {
        super(source);
        this.msg = msg;
    }
}

自定义事件发布者Publisher

NotifyPublisher用于我们事件的发布工作,该类实现了ApplicationContextAware并重写了setApplicationContext 方法,这一步的目的是可以获取我们Spring的应用上下文,因为事件的发布是需要应用上下文来做的.

@Component
@Slf4j
public class NotifyPublisher implements ApplicationContextAware {
    private ApplicationContext ctx; //应用上下文


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.ctx= applicationContext;
    }

    public void publishEvent(int type, String json) {
        ctx.publishEvent(new NotifyEvent(type, json));
    }
}

自定义事件订阅者Listener

最后一步就是实现一个类作为事件的订阅者啦,当事件发布时,会通知订阅者,然后订阅者做相关的处理,比如新用户注册发送事件自动发送欢迎邮件等等。

@Component
@Slf4j
//指定具体的事件类型: E extends ApplicationEvent
public class NotifyListener implements ApplicationListener<NotifyEvent> {
     @Override
    public void onApplicationEvent(NotifyEvent event) {
        log.info("收到事件{}",event.getMsg());
    }
}

@EventListener
Spring 4.2 版本更新的EventListener,可以很方便帮助我们实现事件与方法的绑定,只需要在目标方法上加上EventListener即可。

@Component
public class MqListener {

    @EventListener
    //参数NotifyEvent ,当有NotifyEvent 类型的事件发生时,交给sayHello方法处理
    public void sayHello(NotifyEvent notifyEvent){
         log.info("收到事件{}",event.getMsg());
    }
}

测试

public class AuthenticationCenterApplication implements CommandLineRunner {
	
	//略...

    @Autowired
    private NotifyPublisher mqPublisher;

    @Override
    public void run(String... args) throws Exception {
        AtomicInteger loop = new AtomicInteger(1);
        while (loop.get() < 10) {
            mqPublisher.publishEvent(1, "nihao_" + loop.getAndIncrement());
            TimeUnit.SECONDS.sleep(1);
        }
    }
}

后台打印结果:
在这里插入图片描述
每隔一秒种打印一次数据。

但是可以看到上述的执行内容,全部是由main线程执行的。

异步事件驱动编程

Spring 也提供了@Async 注解来实现异步事件的消费。用起来也很简单,只需要在

  • @EventListener上加上@Async
  • 或者onApplicationEvent方法上添加@Async

springboot开启@EnableAsync 即可支持异步。

@EnableAsync
public class AuthenticationCenterApplication implements CommandLineRunner {
}

执行结果: 在这里插入图片描述

自定义线程池
Springboot默认的异步线程池名为"taskExecutor":org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor, 可以通过注入java.util.concurrent.Executor`进行覆盖:

   @Bean
    public Executor taskExecutor(){
        return new ThreadPoolExecutor(2,
                4,
                1000,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue(5),
                new UserThreadFactory("myAysnc")
        );
    }

    static class UserThreadFactory implements ThreadFactory {
        private final String namePrefix;
        private final AtomicInteger nextId = new AtomicInteger(1);

        UserThreadFactory(String whatFeatureOfGroup) {
            namePrefix = whatFeatureOfGroup + "-pool-";
        }

        @Override
        public Thread newThread(Runnable task) {
            String name = namePrefix + nextId.getAndIncrement();
            Thread thread = new Thread(null, task, name,0);
            return thread;
        }

    }

打印结果:
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章