一、简介
在上一节中,学了各种回调监听器,其中有一种监听器叫做ApplicationListener,它是用来监听发送事件的,在本节中可以利用它来做事件驱动开发。
1.事件驱动开发-理解
(1)事件驱动开发是一种编程范式,它主要面向事件的处理,而不是传统的基于顺序的编程。 事件驱动编程的核心思想是通过事件来驱动程序的执行,而不是基于顺序执行的代码块。
(2)场景(理解)

- 用户登录后,我们基于用户登录的信息,会调用账户服务、优惠服务、系统服务....,一般的代码应该是这样去写的,注入各种各样的服务,如果后续还有操作,继续往下增加对应的业务,但设计模式中我们应该新增开发,对修改要关闭,利用事件以后,我们只需要发送一个事件,其余服务监听这个事件做对应的操作即可

- 事件驱动开发(相关服务监听事件做对应操作)

二、事件驱动开发-实践
1.ApplicationListener回顾
(1)当自定义了该监听器后会进行事件的推送


- 发送请求

- 我们访问对应的地址时,springboot中ApplicationListener会推送对应的事件,那么可以利用它去自定义事件,就能够做到事件驱动的开发
2.驱动开发过程

(1)Controller
package com.yang.controller;
import com.yang.entity.User;
import com.yang.event.EventPublisher;
import com.yang.event.LoginEvent;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class LoginController {
@Resource
private EventPublisher eventPublisher;
/**
* 登录
*/
@GetMapping("/login")
public String login(@RequestParam("username") String username,
@RequestParam("password") String password){
//1、创建事件信息
LoginEvent loginEvent = new LoginEvent(new User(username, password));
//2、发送事件
eventPublisher.sendEvent(loginEvent);
return "successful!";
}
}
(2)Event(组装事件信息,发送事件)
- LoginEvent
package com.yang.event;
import com.yang.entity.User;
import org.springframework.context.ApplicationEvent;
/**
* 登录事件组装
* 要发送的事件都必须继承ApplicationEvent
*/
public class LoginEvent extends ApplicationEvent {
public LoginEvent(User source) {
super(source);
}
}
- EventPublisher:需要继承ApplicationEventPublisherAware(拿到springboot给我们注入的发送事件组件),组件ApplicationEventPublisher发送的事件是广播,所有服务想收该事件都能够收到,收到的顺序是按字母排序的,也可以用@Order注解指定顺序
package com.yang.event;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
@Service
public class EventPublisher implements ApplicationEventPublisherAware {
/**
* 底层发送事件用的组件,SpringBoot会通过ApplicationEventPublisherAware接口自动注入给我们
*
*/
private ApplicationEventPublisher publisher;
/**
* 发送事件
* @param event
*/
public void sendEvent(ApplicationEvent event) {
// 调用底层API发事件
publisher.publishEvent(event);
}
/**
* 会被自动调用,把真正发事件的底层组件给我们注入进来
* @param applicationEventPublisher event publisher to be used by this object
*/
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
}
(3)entity
package com.yang.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private String passwd;
}
(4)Service
-
AccountService:可以实现ApplicationListener<LoginEvent>
package com.yang.service;
import com.yang.entity.User;
import com.yang.event.LoginEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Service;
/**
* ApplicationListener<LoginEvent>表示只接收LoginEvent类型的事件
* 如果是填入ApplicationListener<ApplicationEvent>表示接收所有事件
*/
@Service
public class AccountService implements ApplicationListener<LoginEvent> {
public void addAccountScore(String username){
System.out.println(username + " 加1积分");
}
@Override
public void onApplicationEvent(LoginEvent event) {
System.out.println("AccountService 收到事件 =====>" + event);
User source = (User) event.getSource();
addAccountScore(source.getName());
}
}
-
CouponService:也可以使用注解@EventListener
package com.yang.service;
import com.yang.entity.User;
import com.yang.event.LoginEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
@Service
public class CouponService {
public void sendCoupon(String username) {
System.out.println("给用户" + username + "发送优惠券");
}
@EventListener
public void receiveEvent(LoginEvent event){
System.out.println("CouponService 收到事件 =====>" + event);
User source = (User) event.getSource();
sendCoupon(source.getName());
}
}
(5)运行结果
2024-12-21T23:21:24.809+08:00 INFO 32756 --- [nio-8080-exec-3] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2024-12-21T23:21:24.809+08:00 INFO 32756 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2024-12-21T23:21:24.809+08:00 INFO 32756 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet : Completed initialization in 0 ms
========>事件推送:com.yang.event.LoginEvent[source=User(name=xiaoming, passwd=123456)]
AccountService 收到事件 =====>com.yang.event.LoginEvent[source=User(name=xiaoming, passwd=123456)]
xiaoming 加1积分
CouponService 收到事件 =====>com.yang.event.LoginEvent[source=User(name=xiaoming, passwd=123456)]
给用户xiaoming发送优惠券
========>事件推送:ServletRequestHandledEvent: url=[/login]; client=[0:0:0:0:0:0:0:1]; method=[GET]; servlet=[dispatcherServlet]; session=[null]; user=[null]; time=[24ms]; status=[OK]
1507

被折叠的 条评论
为什么被折叠?



