「本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!」
Spring事件机制(Event)-- 基于观察者模式
当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。
介绍
意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。
何时使用:一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。
优点: 1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。
缺点: 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
本篇文章实现效果: 通过Spring事件机制(Event),实现用户注册成功后,同时发送邮箱以及短信。
本篇文章源码链接:点击下载
实现步骤:
- spring事件发送监听涉及3个部分(步骤):
1.ApplicationEvent:表示事件本身,自定义事件需要继承该类,
可以用来传递数据,比如上述操作,我们需要将用户的邮箱地址传给事件监听器.
--------------------------------------------------------------
2.ApplicationEventPublisherAware:事件发送器,通过实现这个接口,来触发事件.
--------------------------------------------------------------
3.ApplicationListener:事件监听器接口,事件的业务逻辑封装在监听器里面
也可通过注解@EventListener监听事件.
- Demo及注解说明
本Demo基于SpringBoot框架,使用了Lombok插件
@EnableAsync -- 开启 Spring 异步的功能
@EventListener -- 监听事件
@Async -- 异步处理
@Slf4j -- Lombok日志注解
- 在pom.xml中加入web相关依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
- 启动类添加注解@EnableAsync,开启 Spring 异步的功能
@SpringBootApplication
/**
* 开启 Spring 异步的功能
*/
@EnableAsync
public class ObserverPatternApplication {
public static void main(String[] args) {
SpringApplication.run(ObserverPatternApplication.class, args);
}
}
- 创建用户注册事件类(UserRegisterEvent)
public class UserRegisterEvent extends ApplicationEvent {
/**
* 用户名
*/
private String username;
public UserRegisterEvent(Object source, String username) {
super(source);
this.username = username;
}
public String getUsername() {
return username;
}
}
- 创建用户 Service(UserService )
@Service
@Slf4j
public class UserService implements ApplicationEventPublisherAware {
private ApplicationEventPublisher applicationEventPublisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
@Async
public void register(String username) {
log.info("新用户:" + username + ",进行注册...");
System.out.println("------------------------------------------------------------------------------------------------------------------------------");
//触发(发布)事件
applicationEventPublisher.publishEvent(new UserRegisterEvent(this, username));
}
}
- 创建邮箱 Service(EmailService)
@Service
@Slf4j
public class EmailService implements ApplicationListener<UserRegisterEvent> {
@Override
@Async
public void onApplicationEvent(UserRegisterEvent userRegisterEvent) {
log.info("给用户 " + userRegisterEvent.getUsername() + " 发送邮箱...");
System.out.println("------------------------------------------------------------------------------------------------------------------------------");
}
}
- 创建短信 Service(MsgService)
@Service
@Slf4j
public class MsgService {
@EventListener
@Async
public void addCoupon(UserRegisterEvent userRegisterEvent) {
log.info("给用户 " + userRegisterEvent.getUsername() + " 发送短信...");
System.out.println("------------------------------------------------------------------------------------------------------------------------------");
}
}
- 创建测试接口
@RestController
@RequestMapping("/test")
public class TestController {
@Resource
private UserService userService;
@GetMapping("/register")
public String register(String username) {
userService.register(username);
return "success";
}
}
-
直接浏览器或者Postman访问 http://localhost:8080/test/register?username=张三
-
查看控制台打印的日志
往期推荐: SpringBoot集成Jwt(详细步骤+图解) SpringBoot实现自定义异常+全局异常处理(多个异常处理类catch顺序)【详细步骤+图解】 SpringBoot集成MyBatis-Plus以及MyBatis-Plus代码生成工具类(详细步骤+图解)
有什么疑问可评论区提问!