spring注解驱动系列--ApplicationListener研究

一、什么是spring的监听器

Spring事件监听机制可以理解为是一种观察者模式,有数据发布者(事件源,也称为被监听对象)、数据接受者(监听器 listener)、事件对象event。,它们能帮助开发者监听 web 中特定的事件,比如 ServletContext, HttpSession, ServletRequest 的创建和销毁;变量的创建、销毁等等。

二、 ApplicationListener

Spring的事件监听器定义为ApplicationListener,继承java.util.EventListener(Spring还定义了一个注解,也叫EventListener,在spring-context包中,两者是不同的概念。事件监听机制总体可以理解为三部分:发布事件的人---》发布什么事件---》这个事件接受的人

一、spring事件对象event

Spring定义了许多事件对象,事件对象都是继承java.util.EventObject对象,下面是部分事件对象:

 二、spring事件监听器

Spring实现了很多事件监听器的类型,都是继承自ApplicationListener,下面是部分实现类:

监听 ApplicationEvent 及其下面的子事件

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    void onApplicationEvent(E var1);
}

三、使用步骤

一、基于注解驱动

一、需要定义要发布的事件,也就是你要发布啥事件

如果要自定义事件,必须继承Spring定义的接口ApplicationEvent

public class OrderEvent extends ApplicationEvent {
    private String orderId;
    private String userEmail;

    public OrderEvent(Object source, String orderId, String userEmail) {
        super(source);
        this.orderId = orderId;
        this.userEmail = userEmail;
    }

    public String getOrderId() {
        return orderId;
    }

    public String getUserEmail() {
        return userEmail;
    }
}

二、定义事件监听器实现

@Component
public class OrderConfirmationListener {

    @EventListener
    public void handleOrderEvent(OrderEvent event) {
        // 发送订单确认邮件给用户
        String userEmail = event.getUserEmail();
        System.out.println("Sending order confirmation email to " + userEmail);
        // 实际的邮件发送逻辑...
    }
}

三、发布事件

@Service
public class OrderService {
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    public void createOrder(String orderId, String userEmail) {
        // 创建订单逻辑...
        
        // 订单创建后,发布一个订单事件
        OrderEvent orderEvent = new OrderEvent(this, orderId, userEmail);
        applicationEventPublisher.publishEvent(orderEvent);
    }
}

确保所有的事件监听器和订单服务都是Spring容器管理的Bean。当OrderService的createOrder方法被调用时,它会创建一个新的订单并发布一个OrderEvent。Spring容器将自动通知所有监听OrderEvent的监听器,这些监听器将执行相应的业务逻辑,如发送确认邮件、更新库存和记录订单日志。
这样,通过Spring的事件发布/订阅机制,我们可以将业务逻辑解耦,提高代码的可维护性和可扩展性。

二、基于接口

一、和注解类型相似,需要先定义要发布的事件

public class MyEvent extends ApplicationEvent {
    public MyEvent(Object source) {
        super(source);
    }
}

二、编写事件监听器

写一个监听器(ApplicationListener实现类)来监听某个事件(ApplicationEvent及其子类)

public class MyListener2 implements ApplicationListener<MyEvent> {

    @Override
    public void onApplicationEvent(MyEvent event) {
        System.out.println("收到基于接口驱动的事件:" + event);
    }
}

 三、发布事件

public class EventMain2 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext();
        // 注册自定义事件监听器
        context.addApplicationListener(new MyListener2());
        // 启动上下文
        context.refresh();
        // 发布事件,事件源为Context
        context.publishEvent(new MyEvent(context));
        // 结束
        context.close();
    }
}

四、原理

一、ContextRefreshedEvent事件:

这个是第一个收到的事件。

1)、容器创建对象,并调用refresh()进行刷新;
2)、中间还会进行各种对象的注册,最后调用finishRefresh();容器刷新完成会发布ContextRefreshedEvent事件。在publishEvent这个方法当中。

这个事件的发布和自己发布事件原理都是一样的,原理写在了下方

 

二、自己发布事件

一、事件发布流程

之后收到的是自己发布的事件

publishEvent(new ContextRefreshedEvent(this));

一、获取事件的多播器(派发器):getApplicationEventMulticaster()

二、之后会调用multicastEvent(applicationEvent, eventType)这个方法,进行派发事件

@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);
      }
   }
}

1、如果有Executor,可以支持使用Executor进行异步派发;

2、否则,同步的方式直接执行listener方法;invokeListener(listener, event);具体就是拿到listener(监听器)回调onApplicationEvent方法;

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
  Assert.notNull(event, "Event must not be null");
  Object applicationEvent;
  //将事件封装成事件对象ApplicationEvent
  if (event instanceof ApplicationEvent) {
      applicationEvent = (ApplicationEvent)event;
  } else {
      applicationEvent = new PayloadApplicationEvent(this, event);
      if (eventType == null) {
          eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
      }
  }
   广播事件
  if (this.earlyApplicationEvents != null) {
      //earlyApplicationEvents。它是一个set,用来存放一些容器启动时需要发布的事件。
      //在earlyApplicationEvents中的事件被发布、容器彻底启动后,它将被置空
      this.earlyApplicationEvents.add(applicationEvent);
  } else {
      //我们自定义的事件以及容器启动后发送的事件都会走else分支,      重点是这一行代码!!!
      this.getApplicationEventMulticaster().multicastEvent((ApplicationEvent)applicationEvent, eventType);
  }

   如果有父容器,则在父容器内也进行广播
  if (this.parent != null) {
      if (this.parent instanceof AbstractApplicationContext) {
          ((AbstractApplicationContext)this.parent).publishEvent(event, eventType);
      } else {
          this.parent.publishEvent(event);
      }
  }

}

二、事件多播器(派发器) 

一、容器创建对象,会调用refresh()

二、在创建其他对象的过程中,有一步initApplicationEventMulticaster();会初始化ApplicationEventMulticaster(也就是事件派发器);

1、先去容器中找有没有id=“applicationEventMulticaster”的组件;

2、如果没有,this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);    并且加入到容器中,我们就可以在其他组件要派发事件,自动注入这个applicationEventMulticaster;

        

protected void initApplicationEventMulticaster() {
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        // 先去容器中找有没有id=“applicationEventMulticaster”的组件;
   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 {
       // 如果没有自己给一个默认的,并放入到容器中
      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() + "]");
      }
   }
}

三、 容器中有哪些监听器

一、容器创建对象,会调用refresh()

二、在创建其他对象的过程中,有一步registerListeners();

        1、从容器中拿到所有的监听器,把他们注册到applicationEventMulticaster中;

        2、如果上面的监听器没有,会通过监听器类获取对应的监听器名字并注册到派发器中

protected void registerListeners() {
   // Register statically specified listeners first.
   for (ApplicationListener<?> listener : getApplicationListeners()) {
      // 从容器中拿到所有的监听器,把他们注册到applicationEventMulticaster中,这里加入进去主要是在事件派发是,回调监听器的方法
      getApplicationEventMulticaster().addApplicationListener(listener);
   }

   // Do not initialize FactoryBeans here: We need to leave all regular beans
   // uninitialized to let post-processors apply to them!
    // 如果上面的监听器没有,会通过监听器类获取对应的监听器名字并注册到派发器中
   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;
   if (earlyEventsToProcess != null) {
      for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
         getApplicationEventMulticaster().multicastEvent(earlyEvent);
      }
   }
}

四、注解@EventListener原理 

一、使用EventListenerMethodProcessor处理器来解析方法上的@EventListener;

二、EventListenerMethodProcessor主要的就是实现了SmartInitializingSingleton里面的方法 afterSingletonsInstantiated()

        1、ioc容器创建对象并refresh()

        2、然后在refresh()方法中会调用finishBeanFactoryInitialization(beanFactory);初始化剩下的单实例bean;

                a、先创建所有的单实例bean;getBean();

                b、获取所有创建好的单实例bean,判断是否是SmartInitializingSingleton类型的;
 *                   如果是就调用afterSingletonsInstantiated();

 

	public void preInstantiateSingletons() throws BeansException {
		if (logger.isTraceEnabled()) {
			logger.trace("Pre-instantiating singletons in " + this);
		}

		// Iterate over a copy to allow for init methods which in turn register new bean definitions.
		// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// Trigger initialization of all non-lazy singleton beans...
		for (String beanName : beanNames) {
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				if (isFactoryBean(beanName)) {
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					if (bean instanceof FactoryBean) {
						final FactoryBean<?> factory = (FactoryBean<?>) bean;
						boolean isEagerInit;
						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
							isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
											((SmartFactoryBean<?>) factory)::isEagerInit,
									getAccessControlContext());
						}
						else {
							isEagerInit = (factory instanceof SmartFactoryBean &&
									((SmartFactoryBean<?>) factory).isEagerInit());
						}
						if (isEagerInit) {
							getBean(beanName);
						}
					}
				}
				else {
					getBean(beanName);
				}
			}
		}

		// Trigger post-initialization callback for all applicable beans...
		for (String beanName : beanNames) {
			Object singletonInstance = getSingleton(beanName);
			if (singletonInstance instanceof SmartInitializingSingleton) {
				final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
				if (System.getSecurityManager() != null) {
					AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
						smartSingleton.afterSingletonsInstantiated();
						return null;
					}, getAccessControlContext());
				}
				else {
					smartSingleton.afterSingletonsInstantiated();
				}
			}
		}
	}

三、容器关闭会发布ContextClosedEvent 

  • 23
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值