一.介绍
事件驱动编程是一种编程范式,其核心思想是程序的执行由事件来驱动
三个基本要素:事件源(什么事件)、事件监听(处理哪些事件)、事件处理(事件怎么处理)
二.案例:模拟游戏用户登录后需要执行的功能
功能:1.添加用户积分 2.发放优惠券 3.记录用户登录日志
@Service
@Slf4j
public class UserService {
public void addUserScore(String username){
log.info("给用户{}添加积分",username);
}
}
@Service
@Slf4j
public class CouponService {
public void sendCoupon(String username) {
log.info("给{}发放优惠券", username);
}
}
@Service
@Slf4j
public class LoggerService {
public void logUserLogin(String username) {
log.info("记录用户{}登录日志",username);
}
}
@Service
@Slf4j
@RequiredArgsConstructor(onConstructor_ = @Lazy)
public class LoginService {
private final UserService userService;
private final CouponService couponService;
private final LoggerService loggerService;
public void login(String username) {
log.info("用户{}登录",username);
userService.addUserScore(username);
couponService.sendCoupon(username);
loggerService.logUserLogin(username);
}
}
@SpringBootApplication
public class EventDrivenProgrammingApplication {
public static void main(String[] args) {
ConfigurableApplicationContext ioc = SpringApplication.run(EventDrivenProgrammingApplication.class, args);
LoginService loginService = ioc.getBean(LoginService.class);
loginService.login("张三");
}
}
缺点:
1.如果还要新增功能(登录后邮箱提醒),要添加EmailService还要修改LoginService::login方法(违反开闭原则)
2.一个登录服务又掺杂积分、优惠券、日志等服务(违反单一职责)
三.事件驱动方案
1.创建事件类(继承ApplicationEvent)
public class LoginEvent extends ApplicationEvent {
public LoginEvent(String userName) {
//父类构造参数为Object类型 通常保存事件相关数据
super(userName);
}
}
2.发送事件(不再执行具体任务,替换成事件的发出)
@Service
@Slf4j
@RequiredArgsConstructor(onConstructor_ = @Lazy)
public class LoginService {
//使用Spring提供的ApplicationEventPublisher发布事件
private final ApplicationEventPublisher eventPublisher;
public void login(String username) {
log.info("用户{}登录",username);
eventPublisher.publishEvent(new LoginEvent(username));
}
}
3.监听事件并处理
@Service
@Slf4j
public class UserService {
@EventListener
public void addUserScore(LoginEvent loginEvent){
log.info("给用户{}添加积分",loginEvent.getSource());
}
}
@Service
@Slf4j
public class CouponService {
@EventListener
public void sendCoupon(LoginEvent loginEvent) {
log.info("给{}发放优惠券", loginEvent.getSource());
}
}
@Service
@Slf4j
public class LoggerService {
@EventListener
public void logUserLogin(LoginEvent loginEvent) {
log.info("记录用户{}登录日志",loginEvent.getSource());
}
}