文章目录
- Pre
- Code
- 基础工程
- 启动类
- 切入口
- 事件
- 发布事件
- 同步 Listener
- 异步Listener
- 增加@EnableAsync
- 增加 @Async
- 测试
Pre
Spring Boot - Application Events 的发布顺序_ApplicationStartingEvent
Spring Boot - Application Events 的发布顺序_ApplicationEnvironmentPreparedEvent
Spring Boot - Application Events 的发布顺序_ApplicationContextInitializedEvent
Spring Boot - Application Events 的发布顺序_ApplicationPreparedEvent
Spring Boot - Application Events 的发布顺序_ContextRefreshedListener
Spring Boot - Application Events 的发布顺序_ApplicationStartedEvent
Spring Boot - Application Events 的发布顺序_AvailabilityChangeEvent
Spring Boot - Application Events 的发布顺序_ApplicationReadyEvent
Spring Boot - Application Events 的发布顺序_ApplicationFailedEvent
Spring Boot - ApplicationRunner && CommandLineRunner扩展接口
Code
基础工程
启动类
@SpringBootApplication
public class LifeCycleApplication {
/**
* 除了手工add , 在 META-INF下面 的 spring.factories 里增加
* org.springframework.context.ApplicationListener=自定义的listener 也可以
*
* @param args
*/
public static void main(String[] args) {
SpringApplication.run(LifeCycleApplication.class, args);
}
}
META-INF中增加 spring.factories
文件
org.springframework.context.ApplicationListener=\
com.artisan.practise.listeners.SpringBuiltInEventsListener
切入口
package com.artisan.practise.listeners;
import com.artisan.practise.publish.Publisher;
import org.springframework.beans.BeansException;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.boot.context.event.SpringApplicationEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
/**
* @author 小工匠
* @version 1.0
* @mark: show me the code , change the world
*/
public class SpringBuiltInEventsListener implements ApplicationListener<SpringApplicationEvent>, ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void onApplicationEvent(SpringApplicationEvent event) {
System.out.println("SpringApplicationEvent Received - " + event);
// Initializing publisher for custom event
this.initPublisher(event);
}
private void initPublisher(SpringApplicationEvent event) {
if (event instanceof ApplicationReadyEvent) {
this.applicationContext.getBean(Publisher.class).publishEvent();
}
}
}
事件
package com.artisan.practise.events;
import org.springframework.context.ApplicationEvent;
/**
* @author 小工匠
* @version 1.0
* @mark: show me the code , change the world
*/
public class UserCreatedEvent extends ApplicationEvent {
private static final long serialVersionUID = 1L;
private String name;
public UserCreatedEvent(Object source, String name) {
super(source);
this.name = name;
}
public String getName() {
return this.name;
}
}
package com.artisan.practise.events;
/**
* @author 小工匠
* @version 1.0
* @mark: show me the code , change the world
*/
public class UserRemovedEvent {
public String name;
public UserRemovedEvent(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
发布事件
package com.artisan.practise.publish;
import com.artisan.practise.events.UserCreatedEvent;
import com.artisan.practise.events.UserRemovedEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
/**
* @author 小工匠
* @version 1.0
* @mark: show me the code , change the world
*/
@Component
public class Publisher {
@Autowired
private ApplicationEventPublisher publisher;
public void publishEvent() {
System.out.println("========================" + Thread.currentThread().getName());
// Async Event
publisher.publishEvent("I'm Async");
// @EventListener Annotated and ApplicationListener
publisher.publishEvent(new UserCreatedEvent(this, "Artisan"));
publisher.publishEvent(new UserRemovedEvent("Artisan"));
// Conditional Listener
publisher.publishEvent(new UserCreatedEvent(this, "reflectoring"));
publisher.publishEvent(new UserRemovedEvent("reflectoring"));
}
}
同步 Listener
package com.artisan.practise.listeners;
import com.artisan.practise.events.UserCreatedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
/**
* @author 小工匠
* @version 1.0
* @mark: show me the code , change the world
*/
@Component
class UserCreatedListener implements ApplicationListener<UserCreatedEvent> {
@Override
public void onApplicationEvent(UserCreatedEvent event) {
System.out.println(String.format("%s - User created: %s",Thread.currentThread().getName() , event.getName()));
}
}
package com.artisan.practise.listeners;
import com.artisan.practise.events.UserRemovedEvent;
import com.artisan.practise.response.ReturnedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;
/**
* @author 小工匠
* @version 1.0
* @mark: show me the code , change the world
*/
@Component
public class UserRemovedListener {
@EventListener
ReturnedEvent handleUserRemovedEvent(UserRemovedEvent event) {
System.out.println(String.format("%s - User removed (@EventListerner): %s", Thread.currentThread().getName(), event.getName()));
// Spring will send ReturnedEvent as a new event
return new ReturnedEvent();
}
// Listener to receive the event returned by Spring
@EventListener
void handleReturnedEvent(ReturnedEvent event) {
System.out.println(String.format("%s - ReturnedEvent received.", Thread.currentThread().getName()));
}
@EventListener(condition = "#event.name eq 'reflectoring'")
void handleConditionalListener(UserRemovedEvent event) {
System.out.println(String.format("%s - User removed (Conditional): %s", Thread.currentThread().getName(), event.getName()));
}
@TransactionalEventListener(condition = "#event.name eq 'reflectoring'", phase = TransactionPhase.AFTER_COMPLETION)
void handleAfterUserRemoved(UserRemovedEvent event) {
System.out.println(String.format("%s - User removed (@TransactionalEventListener): %s", Thread.currentThread().getName(), event.getName()));
}
}
异步Listener
增加@EnableAsync
启动类增加@EnableAsync
@SpringBootApplication
@EnableAsync
public class LifeCycleApplication {
}
@EnableAsync
是一个在 Spring 框架中使用的注解,它用于启用 Spring 的异步执行功能。当在一个配置类上加上 @EnableAsync
注解时,Spring 容器会设置异步任务执行的支持。这允许你将任务标记为异步,并且可以在不同的线程中执行它们,从而提高应用程序的响应能力和吞吐量。
以下是一些关键点,用以解释 @EnableAsync
注解的功能和用法:
-
异步执行: 在 Spring 应用中,你可以使用
@Async
注解来标记一个方法为异步执行。当方法被调用时,它将在一个单独的线程中运行,而不是在调用线程中立即执行。 -
启用异步执行: 为了使
@Async
注解生效,必须在 Spring 应用程序的配置中启用异步支持。这通常是通过在 Spring 配置类上添加@EnableAsync
注解来实现的。 -
线程池:
@EnableAsync
注解允许你定义一个自定义的线程池,Spring 会使用这个线程池来执行异步任务。如果你没有提供线程池,Spring 会使用默认的线程池。 -
异常处理: 异步方法执行中发生的异常通常不会传递给调用者。
@EnableAsync
支持异常处理配置,允许你定义如何处理这些异常。 -
调度器: 你可以指定一个
TaskScheduler
Bean,Spring 使用它来调度异步任务。默认情况下,Spring 容器会创建一个SimpleAsyncTaskExecutor
实例。 -
顺序执行: 如果你需要确保某些异步方法按照严格的顺序执行,可以使用
@Async
注解的dependsOn
属性来指定依赖关系。
使用 @EnableAsync
注解可以让开发者轻松地构建高并发的应用程序,提高应用程序处理大量并发请求的能力,同时保持代码的清晰和易管理性。在微服务架构和分布式系统中,异步通信是提高系统解耦和性能的关键技术之一。
增加 @Async
增加 @Async
package com.artisan.practise.listeners;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@Component
class AsyncListener {
@Async
@EventListener
void handleAsyncEvent(String event) {
System.out.println(String.format("%s - Async event recevied: %s ", Thread.currentThread().getName(), event));
}
}
@Async
是一个方法级别的注解,在 Spring 框架中用于标识一个方法应该以异步方式执行。当一个方法被标记为 @Async
时,它将在一个单独的线程中运行,而不是在调用它的线程中立即执行。这种方式可以避免阻塞调用线程,从而提高应用程序的响应能力和吞吐量。
以下是一些关于 @Async
注解的关键点:
- 异步方法执行:
@Async
注解允许你将方法的执行放到一个单独的线程中,这样主线程就可以立即返回,继续处理其他任务。 - 线程池:
@Async
注解通常与@EnableAsync
注解一起使用,后者启用了异步支持并定义了一个线程池。异步方法通常会在这个线程池中分配线程来执行。 - 异常处理: 异步方法执行过程中出现的异常通常不会传递给调用者。但是,可以通过配置
AsyncUncaughtExceptionHandler
来处理这些异常。 - 调度器:
@Async
注解可以指定一个TaskScheduler
Bean,它负责调度异步任务的执行。如果没有指定,Spring 会默认使用一个SimpleAsyncTaskExecutor
。 - 顺序执行: 如果需要确保某些异步方法按照严格的顺序执行,可以使用
@Async
注解的dependsOn
属性来指定依赖关系。 - 触发器:
@Async
方法可以由其他@Async
方法触发,这允许创建异步的工作流和回调。 - 注解兼容性:
@Async
注解可以与@Transactional
注解一起使用,但是需要确保事务性注解和异步注解在方法上的使用是兼容的。
异步编程 - 08 Spring框架中的异步执行_TaskExecutor接口和@Async应用篇
异步编程 - 09 Spring框架中的异步执行_@Async注解异步执行原理&源码解析