前言
- 观察者模式在 Spring 中的应用
- 观察者模式,在目标对象发出动作后,触发事件,观察者接收事件,然后执行对应操作。
步骤
- 观察者模型。
- 参考博客。看大佬博客写的文档学习。
- 思维导图。画图讲解清楚流程。(待定)
- 学习方法。怎么样学习。
- 注意点。
- pom 依赖。
- Main 方法编写。
- Controller 层。Http 请求发送使用
- register 层。编写事件类。
- service 层,目标对象,事件创建、发送类。
- service 层,观察者对象1,事件接收、执行类。
- service 层,观察者对象2,事件接收、执行类。
0. 观察者模型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5W3qS7uz-1618732055901)(WEBRESOURCE364d317fc37240740136e2aa75193e62)]
1. 参考博客
- 芋道源码《别再面向 for 循环编程了,Spring 自带的观察者模式就很香!》https://mp.weixin.qq.com/s/HrNEI3WcUKVcgbM3CaJmSg
3. 思维导图
- 测试方案
- 代码编写
4. 学习方法
- 看完模型,复制黏贴代码执行。
5. 注意点
- Spring 使用异步注解 @Async,需要在 Main 方法中注解 @EnableAsync 开启异步。
- 监听事件方式一:实现接口,重写方法
- 监听事件方式二:使用注解,方法入参传入要监听的事件。
6. pom 依赖。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>Spring-mock</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
7. Main 方法编写。
package com.jtfr;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication
@EnableAsync // 开启 Spring 异步的功能
public class SpringBootMain {
public static void main(String[] args) {
SpringApplication.run(SpringBootMain.class, args);
}
}
8. Controller 层。Http 请求发送使用
package com.jtfr.controller;
import com.jtfr.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/demo")
public class DemoController {
@Autowired
private UserService userService;
@GetMapping("/register")
public String register(String username) {
userService.register(username);
return "success";
}
}
9. register 层。编写事件类。
package com.jtfr.register;
import org.springframework.context.ApplicationEvent;
public class UserRegisterEvent extends ApplicationEvent {
/**
* 用户名
*/
private String username;
public UserRegisterEvent(Object source) {
super(source);
}
public UserRegisterEvent(Object source, String username) {
super(source);
this.username = username;
}
public String getUsername() {
return username;
}
}
```
### 10. service 层,目标对象,事件创建、发送类。
```java
package com.jtfr.service;
import com.jtfr.register.UserRegisterEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
// 1. 实现 ApplicationEventPublisherAware 接口,从而将 ApplicationEventPublisher 注入到其中。
@Service
public class UserService implements ApplicationEventPublisherAware {
private Logger logger = LoggerFactory.getLogger(getClass());
private ApplicationEventPublisher applicationEventPublisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
public void register(String username) {
// ... 执行注册逻辑
System.out.println(Thread.currentThread().getName()+"[register][执行用户({}) 的注册逻辑]" + username);
// ... 2. 在执行完注册逻辑后,调用 ApplicationEventPublisher 的 #publishEvent(ApplicationEvent event) 方法,发布 UserRegisterEvent 事件。
applicationEventPublisher.publishEvent(new UserRegisterEvent(this, username));
}
}
```
### 11. service 层,观察者对象1,事件接收、执行类。
```java
package com.jtfr.service;
import com.jtfr.register.UserRegisterEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
@Service
public class CouponService {
private Logger logger = LoggerFactory.getLogger(getClass());
@EventListener // 1. 在方法上,添加 @EventListener 注解,并设置监听的事件为 UserRegisterEvent。这是另一种使用方式!
public void addCoupon(UserRegisterEvent event) {
System.out.println(Thread.currentThread().getName()+"[addCoupon][给用户({}) 发放优惠劵]" + event.getUsername());
}
}
```
### 12. service 层,观察者对象2,事件接收、执行类。
```java
package com.jtfr.service;
import com.jtfr.register.UserRegisterEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
// 1. 实现 ApplicationListener 接口,通过 E 泛型设置感兴趣的事件。
@Service
public class EmailService implements ApplicationListener<UserRegisterEvent> {
@Override // 2. 实现 #onApplicationEvent(E event) 方法,针对监听的 UserRegisterEvent 事件,进行自定义处理。
@Async // 3. 锦上添花,设置 @Async 注解,声明异步执行。毕竟实际场景下,发送邮件可能比较慢,又是非关键逻辑。
public void onApplicationEvent(UserRegisterEvent event) {
System.out.println(Thread.currentThread().getName()+"[onApplicationEvent][给用户({}) 发送邮件]" + event.getUsername());
}
}
```