-
扩展点简述
ApplicationListener提供了一种泛型模板的接口方式,其中有一个唯一方法 onApplicationEvent,需要传入一个实现了ApplicationEvent的泛型对象,采用了观察者设计模式,Spring提供的ApplicationEvent事件主要有4种:ContextRefreshedEvent、ContextClosedEvent、ContextStartedEvent、ContextStoppedEvent。
-
扩展点的生命周期及扩展点的执行时机
属于Spring容器管理生命周期。其类泛型不同,执行的时机不同:Spring官方介绍
ContextRefreshedEvent:通常ConfigurableApplicationContext#refresh()方法时被调用,此时Bean实例化完成且已经可以使用。
ContextClosedEvent:通常ConfigurableApplicationContext#close()调用时被调用,或经由JVM钩子关闭。
ContextStartedEvent、ContextStoppedEvent:通常,用于在显式停止后重新启动Bean。
-
扩展点的作用
比如:可以使用ContextRefreshedEvent事件在这里获取ApplicationContext;
可以做一些需要SpringContext处理的工作,此时所有的Bean都已加载完成且可以使用。
比如我以前拿他筛选Bean上某种注解类型(需要被Spring管理的Bean)。
-
扩展点实战
/**
* 我自己的一段处理路由的spring 的事件监听示例
* 事件种类详见 @See {@link org.springframework.context.event.ApplicationContextEvent} 的实现子类
*/
@Component
public class MappingApplicationListener implements ApplicationListener {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
ApplicationContext context = event.getApplicationContext();
SpringStaticEnv.setApplicationContext(context); // 存储一份上下文信息
/**
* 1. 处理路由注解,如果类上有注解,则与方法注解合并
* 2. 添加到 路由树中(压缩字典树)管理
*/
Map nettyControllerAnnotation = context.getBeansWithAnnotation(NettyController.class);
nettyControllerAnnotation.forEach((nck, ncv) -> {
Class> ncvClass = ncv.getClass();
// 检测类上是否有RouteMapping,如果有,进行解析; 没有则设置一些默认值
RouteMapping classRouteMapping;
String classRouteName = "";
RequestMethod[] classSuppotMethods = null;
if ((classRouteMapping = ncvClass.getAnnotation(RouteMapping.class)) != null) {
classRouteName = classRouteMapping.value();
classSuppotMethods = classRouteMapping.method();
System.out.println("CLass: " + nck + " " +
classRouteName + " " + Arrays.toString(classSuppotMethods));
}
// 检测哪些方法具有RouteMapping:
// yes,将类上与方法上合并 -> 将映射存储至路由树;
// no,跳过;
Method[] methods = ncvClass.getDeclaredMethods();
for (Method method : methods) {
RouteMapping methodRouteMapping;
if ((methodRouteMapping = method.getAnnotation(RouteMapping.class)) != null) {
String methodRouteName = methodRouteMapping.value();
RequestMethod[] methodSuppotMethods = methodRouteMapping.method();
String routeName = classRouteName + methodRouteName;
RequestMethod[] requestMethods = concat(classSuppotMethods, methodSuppotMethods);
Routing routing = new Routing(routeName, method,
requestMethods, context.getBean(ncvClass));
RouterManager.manager().pattern(routeName, routing);
}
}
});
System.out.println("ContextRefreshedEvent 触发。");
}
private static T[] concat(T[] first, T[] second) {
T[] result = Arrays.copyOf(first, first.length + second.length);
System.arraycopy(second, 0, result, first.length, second.length);
return result;
}
}
其他几种简单解释:
@Configuration
public class TestApplicationListener {
/**
* Event raised when an {@code ApplicationContext} gets initialized or refreshed.
* 执行 refresh()方法时被调用
*/
@Component
class A implements ApplicationListener {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println("ContextRefreshedEvent: Spring上下文正在初始化或刷新");
System.out.println(event.getSource());
}
}
/**
* Event raised when an {@code ApplicationContext} gets started.
*/
@Component
class B implements ApplicationListener {
@Override
public void onApplicationEvent(ContextStartedEvent event) {
System.out.println("ContextStartedEvent: Spring上下文正在启动");
}
}
/**
* Event raised when an {@code ApplicationContext} gets stopped.
*/
@Component
class C implements ApplicationListener {
@Override
public void onApplicationEvent(ContextStoppedEvent event) {
System.out.println("ContextStoppedEvent: Spring上下文正在停止");
}
}
/**
* Event raised when an {@code ApplicationContext} gets closed.
*
* 调用JVM钩子,销毁 ApplicationContext上下文被调用
*/
@Component
class D implements ApplicationListener {
@Override
public void onApplicationEvent(ContextClosedEvent event) {
System.out.println("ContextClosedEvent: Spring上下文正在关闭");
}
}
}
- 其他更多使用资料
org.springframework.context.event.EventListener
org.springframework.context.event.ApplicationEventMulticaster
org.springframework.context.ApplicationEventPublisher
org.springframework.context.event.EventListenerMethodProcessor
更多Spring扩展请查看专题Spring开发笔记。