public class LogonEvent extends ApplicationEvent {
private final String userName;
public LogonEvent(Object source, String username) {
super(source);
this.userName = username;
}
public String getUserName() {
return userName;
}
}
@Service
public class LoginEventPublisher {
private final ApplicationEventPublisher applicationEventPublisher;
public LoginEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
public void publishLoginEvent(String username) {
LogonEvent loginEvent = new LogonEvent(this, username);
applicationEventPublisher.publishEvent(loginEvent);
}
}
// 日志处理事件监听器
@Component
public class LoginEventPrintLogListener {
@EventListener
public void handleUserLoginEvent(LogonEvent event) {
String username = event.getUserName();
// 在这里执行处理用户登录事件的逻辑,例如记录日志或触发其他操作
System.out.println("User logged in: " + username);
}
}
// 登录消息通知事件监听器
@Component
public class LoginEventMessageNoticeListener {
@EventListener
public void LoginEventMessageNoticeListener(LogonEvent event) {
String username = event.getUserName();
// 发送消息通知用户
System.out.println("message send User logged in: " + username);
}
}
@Component
public class MyCommandLineRunner implements CommandLineRunner {
private final LoginEventPublisher loginEventPublisher;
public MyCommandLineRunner(LoginEventPublisher loginEventPublisher) {
this.loginEventPublisher = loginEventPublisher;
}
@Override
public void run(String... args) {
// 在应用程序启动后执行的自定义逻辑
System.out.println("MyCommandLineRunner executed!");
// 登录成功
// 登录执行后逻辑
loginEventPublisher.publishLoginEvent("小王");
}
}
2023-10-13 16:04:02.021 INFO 5356 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1250 ms
2023-10-13 16:04:02.382 INFO 5356 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2023-10-13 16:05:31.792 INFO 5356 --- [ main] c.e.s.SpringBootTestMavenApplication : Started SpringBootTestMavenApplication in 200.49 seconds (JVM running for 201.165)
MyCommandLineRunner executed!
message send User logged in: 小王
User logged in: 小王
@SpringBootApplication
// 开启 Async
@EnableAsync
public class SpringBootTestMavenApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootTestMavenApplication.class, args);
}
}
@Component
public class LoginEventPrintLogListener {
@EventListener
// 配置任务异步
@Async
public void handleUserLoginEvent(LogonEvent event) throws Exception {
String username = event.getUserName();
// 在这里执行处理用户登录事件的逻辑,例如记录日志或触发其他操作
System.out.println("User logged in: " + username);
}
}
@FunctionalInterface
public interface ApplicationEventPublisher {
default void publishEvent(ApplicationEvent event) {
publishEvent((Object) event);
}
void publishEvent(Object event);
}
public interface ApplicationEventMulticaster {
void addApplicationListener(ApplicationListener<?> listener);
void addApplicationListenerBean(String listenerBeanName);
void removeApplicationListener(ApplicationListener<?> listener);
void removeApplicationListenerBean(String listenerBeanName);
void removeApplicationListeners(Predicate<ApplicationListener<?>> predicate);
void removeApplicationListenerBeans(Predicate<String> predicate);
void multicastEvent(ApplicationEvent event);
void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);
}
public abstract class ApplicationEvent extends EventObject {
/** use serialVersionUID from Spring 1.2 for interoperability. */
private static final long serialVersionUID = 7099057708183571937L;
/** System time when the event happened. */
private final long timestamp;
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
}
// org.springframework.context.support.AbstractApplicationContext#publishEvent
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
// Decorate event as an ApplicationEvent if necessary
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
}
// Multicast right now if possible - or lazily once the multicaster is initialized
// ApplicationEventMulticaster 未初始化完成时将 applicationEvent 暂存
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
// 获取监听管理器并进行广播
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// Publish event via parent context as well...
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
// org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
// 循环遍历调用监听器
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
// 是否存在线程池 异步执行逻辑
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
// 非异步线程处理
invokeListener(listener, event);
}
}
}
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
// 是否存在 ErrorHandler
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
doInvokeListener(listener, event);
}
}
// org.springframework.context.event.ApplicationListenerMethodAdapter#onApplicationEvent
@Override
public void onApplicationEvent(ApplicationEvent event) {
processEvent(event);
}
public void processEvent(ApplicationEvent event) {
Object[] args = resolveArguments(event);
if (shouldHandle(event, args)) {
// 调用监听器
Object result = doInvoke(args);
if (result != null) {
handleResult(result);
}
else {
logger.trace("No result object given - no result to handle");
}
}
}
protected Object doInvoke(Object... args) {
// 从 spring 容器中通过 getBean() 方法获取监听器Bean
// 因此支持监听器动态加载
Object bean = getTargetBean();
// Detect package-protected NullBean instance through equals(null) check
if (bean.equals(null)) {
return null;
}
ReflectionUtils.makeAccessible(this.method);
try {
return this.method.invoke(bean, args);
}
catch (IllegalArgumentException ex) {
assertTargetBean(this.method, bean, args);
throw new IllegalStateException(getInvocationErrorMessage(bean, ex.getMessage(), args), ex);
}
catch (IllegalAccessException ex) {
throw new IllegalStateException(getInvocationErrorMessage(bean, ex.getMessage(), args), ex);
}
catch (InvocationTargetException ex) {
// Throw underlying exception
Throwable targetException = ex.getTargetException();
if (targetException instanceof RuntimeException) {
throw (RuntimeException) targetException;
}
else {
String msg = getInvocationErrorMessage(bean, "Failed to invoke event listener method", args);
throw new UndeclaredThrowableException(targetException, msg);
}
}
}
# 在核心方法refresh中建立applicationEventMulticaster
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
// 在Spring容器中初始化事件广播器,事件广播器用于事件的发布
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
// 把Spring容器内的事件监听器和BeanFactory中的事件监听器都添加的事件广播器中。
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishrefresh();
# 主要逻辑在 initApplicationEventMulticaster 和 registerListeners
// 初始化事件广播器
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 如果用户手动新建了一个名为applicationEventMulticaster类型为ApplicationEventMulticaster的bean,则将这个bean作为事件广播器
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
// 否则新建一个SimpleApplicationEventMulticaster作为默认的事件广播器
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
// 注册监听器
protected void registerListeners() {
// Register statically specified listeners first.
// 把提前存储好的监听器添加到监听器容器中
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let post-processors apply to them!
// 获取类型是ApplicationListener的beanName集合,此处不会去实例化bean
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// Publish early application events now that we finally have a multicaster...
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
// 如果存在earlyEventsToProcess,提前处理这些事件
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
? 你好,我是 Lorin 洛林,一位 Java 后端技术开发者!座右铭:Technology has the power to make the world a better place.
? 我对技术的热情是我不断学习和分享的动力。我的博客是一个关于Java生态系统、后端开发和最新技术趋势的地方。
? 作为一个 Java 后端技术爱好者,我不仅热衷于探索语言的新特性和技术的深度,还热衷于分享我的见解和最佳实践。我相信知识的分享和社区合作可以帮助我们共同成长。
? 在我的博客上,你将找到关于Java核心概念、JVM 底层技术、常用框架如Spring和Mybatis 、MySQL等数据库管理、RabbitMQ、Rocketmq等消息中间件、性能优化等内容的深入文章。我也将分享一些编程技巧和解决问题的方法,以帮助你更好地掌握Java编程。
? 我鼓励互动和建立社区,因此请留下你的问题、建议或主题请求,让我知道你感兴趣的内容。此外,我将分享最新的互联网和技术资讯,以确保你与技术世界的最新发展保持联系。我期待与你一起在技术之路上前进,一起探讨技术世界的无限可能性。
? 保持关注我的博客,让我们共同追求技术卓越。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。