对于spring 的自定义事件发布与监听

来源:互联网 发布:java工程师的岗位要求 编辑:程序博客网 时间:2024/06/06 03:27

         背景:前几天在项目中有一个模块要修改一个表的数据,发现这个接口经常出现超时的问题,这个问题很大啊,我们采用的是dubbo做远程调用,我已经把接口超时间设置为了8秒,8秒够多了,直接超时了,想把这个方法设置为异步的用runnable来执行还是不可以,时间没法缩减,定位各个语句需要的时间,发现是一个update语句太慢,经头头查询,说给这个表的update语句添加了触发器,这个触发器要对一个大表做删除操作,这个就坑了,然后他扔过来一句这个和业务相关没法改,这样我就不爽了,为何,应为这个update的实时性要求高,而你的那个触发器的实时性可以稍晚一点不影响显示,你可以把他做成一个异步的接口来执行就搞定了,更合理的是这个是一个业务的问题,应该改触发器的实现为消费者生产者模型,唉,明知不合理还不可为。我晚上想了一下,用生产者消费者模型,这个需要引入消息中间件,这样部署需要的东西就多了,为了一个小的方法搞这个消息中间件,有点小题大做了,我发现spring可以自定义事件,用事件触发的观察者模式就可以解决了,我们定义了一个事件继承ApplicationEvent来定义一个事件,定义一个事件监听器,继承ApplicationListener就可以了,发现这样还是没有改善,为何经查询这样的方式还是同步的,所以时间上没有减少,我查询发现spring 4.x版本支持@Async这个注解就是表示该方法是异步执行的,我只加了这个看了看发现还是并行的,查询发现要开启异步执行,如何开启?如何spring采用@Configure这种方式来定义配置可以在这个类上加上@EnableAsync就好了,如果是xml配置的,需要加上:

<bean id="taskExecutor" 
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="5" />
<property name="maxPoolSize" value="10" />
<property name="queueCapacity" value="25" />
</bean>
这样就好了,这样就可以异步了。

代码见附件:

自定义事件

public class NewEvent extends ApplicationEvent {
    public NewEvent(Object source) {
        super(source);
    }
}

发布事件类:

@Component
public class EventPublish {
    @Autowired
    private ApplicationContext applicationContext;
    public void publishEvent(String message){
        applicationContext.publishEvent(new NewEvent(message));
    }
}


监听事件类:

@Component
public class EventListenter implements ApplicationListener<NewEvent> {
    @Override
    @Async
    public void onApplicationEvent(final NewEvent newEvent) {
       System.out.println("start ---todo");
                long startTime=System.nanoTime();
                try {
                    Thread.sleep(2000l);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Object source=   newEvent.getSource();
                System.out.println("---message---"+source.toString());
                System.out.println("all used time---"+(System.nanoTime()-startTime));


    }
}


     在近期在 HandlerInterceptorAdapter中我使用事件发布实现异步日志的记录,在这个实践过程中,出现了事件发布一次,而被监听器执行了两次,这个经过我的排查,可能是项目是web项目,在扫描中被@Component被注解扫描了,在webapplicationContext与另一个applicationContext中,出现了两次,所以事件发布一次,监听执行了两次,如何解决这个问题,有两种方式,一种是去掉ApplicationListener上的那个@Component注解,在application.xml中,加上<bean id="eventlistenter" class="com.zhihai.event.EventListenter" />来配置,这样就可以解决了,另一个就是在使用的地方通过ApplicationContext来获取这个EventPublish 来发布任务,这种方式别用@Resource 来注入EventPublish  。这样就搞定了。 


原创粉丝点击