SpringBoot下使用自定义监听事件

事件机制是Spring的一个功能,目前我们使用了SpringBoot框架,所以记录下事件机制在SpringBoot框架下的使用,同时实现异步处理。事件机制其实就是使用了观察者模式(发布-订阅模式)。

Spring的事件机制经过如下流程:

  • 1、自定义事件,继承org.springframework.context.ApplicationEvent抽象类
  • 2、定义事件监听器,实现org.springframework.context.ApplicationListener接口
  • 3、在Spring容器中发布事件

SpringBoot的实例程序

实现一个保存用户的时候,向用户提供的邮箱发送一封邮件的功能,同时采用异步处理。

自定义事件

import org.springframework.context.ApplicationEvent;

public class EmailEvent extends ApplicationEvent {

	private static final long serialVersionUID = 3733891603598996786L;

	private String emailAddress;

	public EmailEvent(String emailAddress) {
		super(emailAddress);
		this.emailAddress = emailAddress;
	}

	public String getEmailAddress() {
		return emailAddress;
	}

	public void setEmailAddress(String emailAddress) {
		this.emailAddress = emailAddress;
	}
}

定义事件监听器

import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Component
public class EmailEventListener implements ApplicationListener<EmailEvent> {

	private static Logger log = LoggerFactory.getLogger(EmailEventListener.class);

	// 异步处理
	@Async
	@Override
	public void onApplicationEvent(EmailEvent event) {
		log.info("监听到事件--邮箱地址:" + event.getEmailAddress());

		//模拟处理的耗时3s
		try {
			TimeUnit.SECONDS.sleep(3);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		log.info("事件处理完成");
	}

}

发布事件

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class EmailEventPublish {

	@Autowired
	private ApplicationContext applicationContext;

	public void publishEvent(String emailAddress) {
		EmailEvent event = new EmailEvent(emailAddress);
		applicationContext.publishEvent(event);
	}

}

调用事件

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.example.demo.event.EmailEventPublish;


@RestController
public class EventController {
	private static Logger log = LoggerFactory.getLogger(EventController.class);

	@Autowired
	private EmailEventPublish emailEventPublish;

	@RequestMapping("/event")
	public void publishEvent(@RequestParam String emailAddress) {
		// 发布事件 -- 采用异步处理
		emailEventPublish.publishEvent(emailAddress);

		// 正常该语句先执行
		log.info("Controller业务处理");
	}
}

结果

访问如下地址

http://localhost:8080/[email protected]

结果为

2023-08-04 21:21:14.338  INFO 6400 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring FrameworkServlet 'dispatcherServlet'
2023-08-04 21:21:14.338  INFO 6400 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization started
2023-08-04 21:21:14.370  INFO 6400 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 32 ms
2023-08-04 21:21:14.429  INFO 6400 --- [nio-8080-exec-1] .s.a.AnnotationAsyncExecutionInterceptor : No task executor bean found for async processing: no bean of type TaskExecutor and no bean named 'taskExecutor' either
2023-08-04 21:21:14.534  INFO 6400 --- [nio-8080-exec-1] c.e.demo.controller.EventController      : Controller业务处理
2023-08-04 21:21:14.535  INFO 6400 --- [cTaskExecutor-1] c.example.demo.event.EmailEventListener  : 监听到事件--邮箱地址:[email protected]
2023-08-04 21:21:17.536  INFO 6400 --- [cTaskExecutor-1] c.example.demo.event.EmailEventListener  : 事件处理完成

上述结果可知是实现了异步处理,先打印了事件之后的程序,等时间到再执行监听程序的代码。

实现异步处理就是在监听事件执行业务代码的方法上添加@Async注解,同时在启动类上添加@EnableAsync即可。

上面的日志还提到了TaskExecutor,这是如果有自定义的线程池就会去调用,如果没有就用默认的。我们也可以自己定义一个TaskExecutor

import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.Nullable;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

@EnableAsync
@Configuration
public class ThreadPool implements AsyncConfigurer {
	@Nullable
	@Override
	@Bean("taskExecutor")
	public Executor getAsyncExecutor() {
		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
		// 线程池创建时候初始化的线程数
		executor.setCorePoolSize(10);
		// 线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
		executor.setMaxPoolSize(20);
		// 用来缓冲执行任务的队列
		executor.setQueueCapacity(200);
		// 允许线程的空闲时间60秒
		executor.setKeepAliveSeconds(60);
		// 线程池名的前缀
		executor.setThreadNamePrefix("taskExecutor-");
		// 线程池对拒绝任务的处理策略
		executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
		executor.initialize();
		return executor;
	}

	@Nullable
	@Override
	public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
		return null;
	}
}

结果

2023-08-04 21:27:36.507  INFO 7848 --- [nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring FrameworkServlet 'dispatcherServlet'
2023-08-04 21:27:36.507  INFO 7848 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization started
2023-08-04 21:27:36.537  INFO 7848 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 30 ms
2023-08-04 21:27:36.757  INFO 7848 --- [nio-8080-exec-2] c.e.demo.controller.EventController      : Controller业务处理
2023-08-04 21:27:36.757  INFO 7848 --- [ taskExecutor-1] c.example.demo.event.EmailEventListener  : 监听到事件--邮箱地址:[email protected]
2023-08-04 21:27:39.757  INFO 7848 --- [ taskExecutor-1] c.example.demo.event.EmailEventListener  : 事件处理完成

可知是使用我们定义的线程池[ taskExecutor-1]

总结

Spring的事件机制是一个很实用的一个功能,在监听和异步处理相关的功能比较适合。

猜你喜欢

转载自blog.csdn.net/flash_love/article/details/132121235
今日推荐