aware,事件的使用
1、aware接口的使用例子
通过Aware接口、ApplicationContextAwareProcessor bean后处理器,将IOC容器中的组件在创建bean的时候通过BeanPostprocessor接口中的postProcessBeforeInitialization方法赋值到需要的地方。
有一些组件也可以通过自动注入的方式获取,具体哪些可以看IOC刷新主流程的第三步。
@Component
public class UseApplicationContext implements ApplicationContextAware{
private ApplicationContext applicationContext;
public ApplicationContext getApplicationContext() {
return applicationContext;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
后处理器关键方法
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof Aware) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
}
2、事件派发的使用例子
2.1、通过继承的方式
定义监听类,这个需要添加到容器中。这个是泛型的接口,可以指定监听感兴趣的事件源。
public class ApplicationListenerDemo implements ApplicationListener<MyApplicationEvent> {
@Override
public void onApplicationEvent(MyApplicationEvent event) {
System.out.println(event);
}
}
定义事件源
public class MyApplicationEvent extends ApplicationEvent {
public MyApplicationEvent(Object source) {
super(source);
}
}
发布事件,获取应用上下文,手动发布事件
AnnotationConfigApplicationContext context = getContext(ExtConfig.class);
context.publishEvent(new MyApplicationEvent("我的事件"));
2.2、通过注解的方式
这个和上面唯一不同的就是时间监听的定义
public class ApplicationListenerAnnotationDemo {
// classes 指定感兴趣的事件源
@EventListener(classes = {MyApplicationEvent.class})
public void customEvent(MyApplicationEvent event){
System.out.println("ApplicationListenerDemo.customEvent==========="+event);
}
}
2.3、执行过程的分析
context.publishEvent()会将事件的派发委托给IOC容器刷新中在第八步初始化好的事件派发器。默认的是SimpleApplicationEventMulticaster
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
// 找到合适的监听器遍历派发,这个就是对泛型和注解指定事件源的支持
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
// 异步支持,需要设置,默认的是同步
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
// 事件派发
invokeListener(listener, event);
}
}
}
事件派发,这个流程还是挺清楚的,看看有没有设置异常处理,默认无;doInvokeListener这个方法就是具体的派发实现了。
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
doInvokeListener(listener, event);
}
}
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception and just log a debug message.
Log logger = LogFactory.getLog(getClass());
if (logger.isDebugEnabled()) {
logger.debug("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
这个地方是直接调用ApplicationListener#onApplicationEvent,第一种方式好理解。事件监听器通过bean的后处理器完成,即org.springframework.context.support.ApplicationListenerDetector#postProcessAfterInitialization
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof ApplicationListener) {
// potentially not detected as a listener by getBeanNamesForType retrieval
Boolean flag = this.singletonNames.get(beanName);
if (Boolean.TRUE.equals(flag)) {
// singleton bean (top-level or inner): register on the fly
this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
}
else if (Boolean.FALSE.equals(flag)) {
if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
// inner bean with other scope - can't reliably process events
logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
"but is not reachable for event multicasting by its containing ApplicationContext " +
"because it does not have singleton scope. Only top-level listener beans are allowed " +
"to be of non-singleton scope.");
}
this.singletonNames.remove(beanName);
}
}
return bean;
}
第二种方式明明没有实现这个接口,为什么能向上转型成这个接口的类型。
这个其实看EventListener注解源码注释可以看到@see EventListenerMethodProcessor,那么这个类应该就是关键了,这个类是SmartInitializingSingleton的接口,会在所有的bean实例化完成之后执行afterSingletonsInstantiated这个方法。
这个处理的流程,遍历所有的bean;查找这个bean中所有添加了EventListener注解的方法;通过DefaultEventListenerFactory#createApplicationListener创建一个ApplicationListener并添加到事件派发器的事件监听集合。