SpringBoot重点详解--事件监听

本文详细介绍了SpringBoot中自定义事件监听的过程,并演示了如何监听SpringBoot启动过程中的各种事件。

目录

自定义事件监听

Springboot 启动事件监听


Springboot 事件监听为 Bean 与 Bean 之间的消息通信提供支持:当一个 Bean 做完一件事以后,通知另一个 Bean 知晓并做出相应处理,此时,需要后续 Bean 监听当前 Bean 所发生的事件。  

自定义事件监听

在 Springboot 中实现自定义事件监听大致可以分为以下四个步骤:

  • 自定义事件,一般是继承 ApplicationEvent 抽象类;
  • 定义事件监听器,一般是实现 ApplicationListener 接口;
  • 注册监听器;
  • 发布事件。

 第一步:自定义事件,一般是继承 ApplicationEvent 抽象类。 

import org.springframework.context.ApplicationEvent;

/**
 * 自定义事件,继承 ApplicationEvent
 * @author pjli
 */
public class MyApplicationEvent extends ApplicationEvent {

	private static final long serialVersionUID = 1L;

	public MyApplicationEvent(Object source) {
		super(source);
		System.out.println("触发 MyApplicationEvent 事件...");
	}

}

第二步:定义事件监听器,一般是实现 ApplicationListener 接口。  

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

/**
 * 事件监听器,实现 ApplicationListener 接口
 * @author pjli
 */

@Component
public class MyApplicationListener implements ApplicationListener<MyApplicationEvent>{

	
	@Override
	public void onApplicationEvent(MyApplicationEvent event) {
		System.out.println("监听到:"+event.getClass().getName()+"事件...");
	}

}

第三步:注册监听器,有以下五种方式。

方式一:在启动类中,使用 ConfigurableApplicationContext.addApplicationListener() 方法注册。 

ConfigurableApplicationContext context = SpringApplication.run(MyApplication.class, args);
// 注册 MyApplicationListener 事件监听器
context.addApplicationListener(new MyApplicationListener());

方式二:使用 @Component 等注解将事件监听器纳入到 Spring 容器中管理。  

@Component
public class MyApplicationListener implements ApplicationListener<MyApplicationEvent>{ //内容同上,此处省略 }

方式三:在 Springboot 核心配置文件 application.properties 中增加 context.listener.classes = [ 监听器全类名 ]。 

context.listener.classes=com.pengjunlee.listener.MyApplicationListener

该 context.listener.classes 配置项在 DelegatingApplicationListener 类的属性常量中指定。

方式四:使用 @EventListener 注解自动生成并注册事件监听器。 

import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class MyEventHandler {

	@EventListener
	public void listenMyApplicationEvent(MyApplicationEvent event) {
		System.out.println("监听到:" + event.getClass().getName() + "事件...");
	}

}

方式五:通过在 CLASSPATH/META-INF/spring.factories 中添加 org.springframework.context.ApplicationListener = [ 监听器全类名 ] 配置项进行注册.  

# Application Listeners
org.springframework.context.ApplicationListener=com.pengjunlee.listener.MyApplicationListener

第四步:发布事件。

在程序启动类中可以使用 ApplicationContext.publishEvent() 发布事件,完整代码如下。  

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

import com.pengjunlee.listener.MyApplicationEvent;
import com.pengjunlee.listener.MyApplicationListener;

@SpringBootApplication
public class MyApplication {
	public static void main(String[] args) {
		ConfigurableApplicationContext context = SpringApplication.run(MyApplication.class, args);
		// 注册 MyApplicationListener 事件监听器
		context.addApplicationListener(new MyApplicationListener());
		// 发布 MyApplicationEvent 事件
		context.publishEvent(new MyApplicationEvent(new Object()));
		// context.getBean(MyEventHandler.class).publishMyApplicationEvent();
		context.close();
	}
}

注意:可以通过以下代码将 ApplicationContext 注入到 Bean 中用来发布事件。  

@Autowired
ApplicationContext applicationContext;

Springboot 启动事件监听

除了可以对自定义的事件进行监听,我们还能够监听 Springboot 的启动事件,Springbootg 共定义了以下5 种启动事件类型:

  • ApplicationStartingEvent:应用启动事件,在调用 SpringApplication.run() 方法之前,可以从中获取到 SpringApplication 对象,进行一些启动前设置。
  • ApplicationEnvironmentPreparedEvent:Environment准备完成事件,此时可以从中获取到 Environment 对象并对其中的配置项进行查看或者修改。
  • ApplicationPreparedEvent:ApplicationContext准备完成事件,接下来 Spring 就能够向容器中加载 Bean 了 。
  • ApplicationReadyEvent:应用准备完成事件,预示着应用可以接收和处理请求了。
  • ApplicationFailedEvent:应用启动失败事件,可以从中捕获到启动失败的异常信息进行相应处理,例如:添加虚拟机对应的钩子进行资源的回收与释放。

为了验证各个启动事件发生的前后,编写一个测试类进行测试,测试代码如下。 

import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.context.event.ApplicationFailedEvent;
import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.boot.context.event.ApplicationStartingEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;

/**
 * Springboot 启动事件测试
 * @author pjli
 */
@SpringBootApplication
public class MySpringBootApplication {
	public static void main(String[] args) {
		SpringApplication springApplication = new SpringApplication(MySpringBootApplication.class);
		// 添加 ApplicationStartingEvent 事件监听器
		springApplication.addListeners((ApplicationListener<ApplicationStartingEvent>) event -> {
			System.out.println("触发 ApplicationStartingEvent 事件...");
			SpringApplication application = event.getSpringApplication();
			application.setBannerMode(Banner.Mode.OFF);
		});
		// 添加 ApplicationEnvironmentPreparedEvent 事件监听器
		springApplication.addListeners((ApplicationListener<ApplicationEnvironmentPreparedEvent>) event -> {
			System.out.println("触发 ApplicationEnvironmentPreparedEvent 事件...");
			ConfigurableEnvironment environment = event.getEnvironment();
			System.out.println("event.name=" + environment.getProperty("event.name"));
		});
		// 添加 ApplicationPreparedEvent 事件监听器
		springApplication.addListeners((ApplicationListener<ApplicationPreparedEvent>) event -> {
			System.out.println("触发 ApplicationPreparedEvent 事件...");
			ConfigurableApplicationContext context = event.getApplicationContext();
			System.out.println("Application context name:" + context.getDisplayName());
		});
		// 添加 ApplicationReadyEvent 事件监听器
		springApplication.addListeners((ApplicationListener<ApplicationReadyEvent>) event -> {
			System.out.println("触发 ApplicationReadyEvent 事件...");
		});
		// 添加 ApplicationFailedEvent 事件监听器
		springApplication.addListeners((ApplicationListener<ApplicationFailedEvent>) event -> {
			System.out.println("触发 ApplicationFailedEvent 事件...");
			Throwable t = event.getException();
			System.out.println("启动失败:" + t.getMessage());
		});
		ConfigurableApplicationContext context = springApplication.run(args);

		context.close();
	}
}

当应用正常启动时,打印内容如下:  

触发 ApplicationStartingEvent 事件...
触发 ApplicationEnvironmentPreparedEvent 事件...
event.name=pengjunlee
触发 ApplicationPreparedEvent 事件...
Application context name:org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@49e202ad
触发 ApplicationReadyEvent 事件...

当应用重复启动两次,由于端口被占用而启动失败时,打印内容如下:  

触发 ApplicationStartingEvent 事件...
触发 ApplicationEnvironmentPreparedEvent 事件...
event.name=pengjunlee
触发 ApplicationPreparedEvent 事件...
Application context name:org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@49e202ad
触发 ApplicationFailedEvent 事件...
启动失败:Connector configured to listen on port 8080 failed to start

由此可以看出 Springboot 启动事件的发生顺序是:Starting -->EnvironmentPrepared --> Prepared-->Ready/Failed

本文项目源码已上传至优快云,资源地址:https://download.youkuaiyun.com/download/pengjunlee/10332845  

<think>好的,用户想了解Vue和Spring Boot结合使用SSE的实现原理及用法,需要详细的教程和示例代码。首先,我需要回忆一下SSE的基本概念。SSE是服务器发送事件,允许服务器主动向客户端推送数据,基于HTTP长连接,适用于实时更新场景,比如股票价格、新闻推送等。 接下来,用户提到Vue和Spring Boot的结合,所以需要分两部分考虑:后端Spring Boot如何实现SSE,以及前端Vue如何接收和处理这些事件。根据引用[1],Spring Boot 3中使用响应式编程可以更高效地实现SSE,可能涉及WebFlux模块。但用户提供的引用中没有直接提到SSE的具体实现步骤,可能需要结合常规的Spring Boot知识。 首先,后端部分。Spring Boot中实现SSE通常使用SseEmitter类,这个类在Spring Web模块中。需要创建一个控制器,返回SseEmitter对象,并通过它发送事件。可能需要参考引用[2]中的依赖,比如Spring Web和可能涉及的安全性Spring Security,但用户的问题主要关注SSE,所以重点在创建控制器和发送事件。 然后前端Vue部分,需要使用EventSource API来连接SSE端点,监听消息事件。Vue组件中在生命周期钩子如mounted()中建立连接,处理接收到的数据,并更新响应式数据以触发视图更新。同时要注意在组件销毁时关闭连接,避免内存泄漏。 示例代码方面,后端需要创建一个REST控制器,返回SseEmitter,并异步发送数据。前端在Vue组件中使用EventSource,处理onmessage事件,将数据绑定到data属性,并在模板中渲染。可能需要处理错误和连接关闭的情况,保证稳定性。 用户可能还会关心跨域问题,所以后端需要配置CORS,或者在Spring Security中允许相关端点。引用[2]提到了Spring Security的依赖,可能需要配置安全策略,但用户的问题可能不需要深入安全部分,除非特别提到。 另外,引用[3]提到Vue+Spring Boot的运行原理,开发流程是后端接口MVC开发,前端处理后端请求和渲染。SSE属于后端主动推送,所以前端需要持续监听,而不是传统的请求-响应模式。 总结步骤:后端创建SSE端点,使用SseEmitter发送事件;前端Vue使用EventSource连接,处理事件并更新界面。需要确保依赖正确,比如Spring Web,以及处理可能的跨域问题。示例代码需要展示基本实现,包括后端控制器的创建和前端Vue组件的集成。</think>### Vue与Spring Boot整合SSE实现详解 #### 一、技术原理 SSE(Server-Sent Events)基于HTTP协议实现服务器到客户端的单向通信,采用长连接机制保持通信通道。与WebSocket相比,SSE更轻量且天然支持断线重连[^1]。 技术实现流程: 1. 客户端通过`EventSource`建立SSE连接 2. Spring Boot使用`SseEmitter`对象管理连接 3. 服务器通过`send()`方法主动推送数据 4. Vue接收数据后触发响应式更新 #### 二、Spring Boot实现 1. 添加依赖(pom.xml) ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> ``` 2. SSE控制器实现 ```java @RestController @RequestMapping("/sse") public class SseController { private final Map<String, SseEmitter> emitters = new ConcurrentHashMap<>(); @GetMapping("/connect") public SseEmitter connect() { SseEmitter emitter = new SseEmitter(3600_000L); // 设置1小时超时 String clientId = UUID.randomUUID().toString(); emitters.put(clientId, emitter); emitter.onCompletion(() -> emitters.remove(clientId)); emitter.onTimeout(() -> emitters.remove(clientId)); return emitter; } @Async public void sendData(String data) { emitters.forEach((id, emitter) -> { try { emitter.send(SseEmitter.event() .data(data) .id(id) .reconnectTime(5000)); } catch (IOException e) { emitter.complete(); emitters.remove(id); } }); } } ``` #### 三、Vue前端实现 1. 创建SSE连接组件 ```vue <template> <div> <h3>实时数据:{{ message }}</h3> </div> </template> <script> export default { data() { return { message: '', eventSource: null } }, mounted() { this.eventSource = new EventSource('http://localhost:8080/sse/connect'); this.eventSource.onmessage = (event) => { this.message = event.data; }; this.eventSource.onerror = (error) => { console.error('SSE连接错误:', error); this.eventSource.close(); }; }, beforeUnmount() { if (this.eventSource) { this.eventSource.close(); } } } </script> ``` #### 四、关键配置要点 1. 跨域处理(Spring Boot配置) ```java @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/sse/**") .allowedOrigins("http://localhost:8081") .allowedMethods("GET"); } } ``` 2. 心跳机制(防止连接超时) ```java @Scheduled(fixedRate = 30000) public void sendHeartbeat() { sendData("SYSTEM_HEARTBEAT:" + System.currentTimeMillis()); } ``` #### 五、应用场景示例 1. 实时股票行情推送 2. 物流状态跟踪 3. 即时新闻推送 4. 在线考试计时系统 $$ \text{通信可靠性公式:} R = 1 - \prod_{i=1}^{n}(1 - p_i) $$ 其中$p_i$表示单个消息的到达概率,$n$为消息重试次数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值