Spring事件与监听
背景:
上周公司codereview的时候,看到有段代码使用到了spring的事件监听。原先没了解过,所以在网上找了一些资料学习了下。
介绍:
下面的描述都是摘抄过来的。
Spring 的事件(Application Event)为 Bean 与 Bean 之间的消息通信提供了支持。当一个 Bean 处理完一个任务之后,希望另一个 Bean 知道并能做相应的处理,这时我们就需要让另一个 Bean 监听当前 Bean 所发送的时间。(观察者模式)
Spring 的事件需要遵循以下流程:
- 自定义事件,集成 ApplicationEvent。
- 定义事件监听器,实现 ApplicationListener。
- 使用容器发布事件。
简单理解就是为系统业务逻辑之间进行了解耦,提高可扩展性以及可维护性。事件发布者并不需要考虑谁去监听,监听具体的实现内容是什么,发布者的工作只是为了发布事件而已。
代码实例:
1.自定义事件,必须继承ApplicationEvent,实现构造方法。
public class UserEvent extends ApplicationEvent {
private BaseBean baseBean;
/**
* 重写构造函数
* @param source 发生事件的对象
*/
public UserEvent(Object source, BaseBean baseBean) {
super(source);
this.baseBean = baseBean;
}
public BaseBean getBaseBean() {
return baseBean;
}
public void setBaseBean(BaseBean baseBean) {
this.baseBean = baseBean;
}
}
2.事件监听器,监听方法的实现有很多中可以使用注解,也可以实现接口ApplicationListener
@Component
public class UserBeanListener {
/**
* 监听实现方法
* @param event 监听事件
*/
@EventListener
public void register(UserEvent event) {
System.out.println("UserBeanListener: " + event.getBaseBean().getName());
}
}
3.发布事件
@Service
public class RegisterService {
@Autowired
private ApplicationContext applicationContext;
public void register() {
/*
* 这里的UserA 和 UserB 都是BaseBean的子类
*/
UserA a = new UserA();
a.setName("a");
UserB b = new UserB();
b.setName("b");
// 发布事件 UserEvent
applicationContext.publishEvent(new UserEvent(this, a));
// 发布事件 UserEvent
applicationContext.publishEvent(new UserEvent(this, b));
}
}
4.控制器,为了看效果才加了这个控制器,其实完成上面3步就已经实现了spring的事件与监听
@RestController
public class UserController {
@Autowired
private RegisterService registerService;
@RequestMapping(value = "/register", method = RequestMethod.GET)
public void register() {
registerService.register();
}
}
5.效果
总结:
1.首先事件的发布与监听是一个同步的过程(同事当时争论过,所以特意试了下),就像上面代码中先发布了UserA的事件,一定会等到UserA的事件监听器的业务逻辑执行完(即UserBeanListener的register方法执行完),再发布UserB的事件。如果想让事件的监听器实现异步处理,可以在使用@Async注解(放在UserBeanListener的register上)。
2.如果发布的事件是一个基类(BaseEvent),同时实现了基类事件的监听(BaseEventListener)与子类事件的监听(UserEventListener)。这时候发布一个子类的事件,则会出现编译可以正常通过,服务也能起来。但实际运行时报错的情况。原因还没仔细看过...
3.事件与监听器的配对是通过事件的类型与监听器方法中的参数类型确定的。