spring监听器
一、ApplicationListener接口
作用:监听容器中发布的事件,完成事件驱动开发
实现ApplicationListener接口
//如果要写实现类就得实现这个接口
public interface ApplicationListener<E extends ApplicationEvent> //泛型是要监听的事件,监听ApplicationEvent及其下面的子事件。即我们要发布事件,这个事件应该是ApplicationEvent的子类
extends EventListener {//处理一个事件
//事件到达以后,出触发该方法
void onApplicationEvent(E event);
}
1 自定义实现
@Component //把监听器加入到容器中
public class MyApplicationListener //写一个监听器来监听某个事件(ApplicationEvent及其子类)
implements ApplicationListener<ApplicationEvent> {
//当容器中发布此事件以后,方法触发//默认的话我们会收到ContextRefreshedEvent和ContextClosedEvent两个事件,即容器刷新完和关闭的事件。而还有两个事件是cotextStartedEvent和ContextStopedEvent事件没有使用
@Override
public void onApplicationEvent(ApplicationEvent event) {
// TODO Auto-generated method stub
System.out.println("收到事件:"+event);//分为开启、关闭
}
}
// 也可以@EventListener
@Service
public class UserService {
@EventListener(classes={ApplicationEvent.class})//原理:使用EventListenerMethodProcessor处理器解析方法上的@EventListener // 可以看EventListenerMethodProcessor
public void listen(ApplicationEvent event){
System.out.println("UserService。。监听到的事件:"+event);
}
}
2 自己发布事件
applicationContext.publishEvent(new ApplicationEvent(new String("我发布的事件"))
public class IOCTest_Ext {
@Test
public void test01(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ExtConfig.class);
//自己发布事件;//这里我们发布了一个容器时间
applicationContext.publishEvent(new ApplicationEvent(new String("我发布的事件")) {
});
applicationContext.close();
}
}
//我们这里发布publish了事件,在MyApplicationListener就会监听到,并传入到event参数,此时就打印出了2+1=3个事件
二、事件监听器流程
原理:
* ContextRefreshedEvent、IOCTest_Ext$1[source=我发布的时间]、ContextClosedEvent;
* 1)、ContextRefreshedEvent事件:
* 1)、容器创建对象:refresh();
* 2)、⑫finishRefresh();容器刷新完成会发布ContextRefreshedEvent事件
* 2)、自己发布事件;
* 3)、容器关闭会发布ContextClosedEvent;
*
* 【事件发布流程】:
* 3)、publishEvent(new ContextRefreshedEvent(this));
* 1)、获取事件的多播器(派发器):getApplicationEventMulticaster()
* 2)、multicastEvent派发事件:
* 3)、获取到所有的ApplicationListener;
* for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
* 1)、如果有Executor,可以支持使用Executor进行异步派发;
* Executor executor = getTaskExecutor();
* 2)、否则,同步的方式直接执行listener方法;invokeListener(listener, event);
* 拿到listener回调onApplicationEvent方法;
三、refresh中发布事件的阶段
技巧:在onApplicationEvent方法上加断点后,debug
首先收到ContextRefreshEvent事件,执行的时机是refresh方法的最后一个方法
// 实例化剩余的单例bean
finishBeanFactoryInitialization();
// refresh的最后一步:发布事件 //在他之前有initApplicationEventMulticaster();
finishRefresh();
(1)finishRefresh()
protected void finishRefresh() {
// Initialize lifecycle processor for this context.
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh();
//发布事件,new了一个事件 容器刷新完成
publishEvent(new ContextRefreshedEvent(this));//容器刷新完成,发布了一个事件
// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}
(2)publishEvent
- 获取多播器
- 多播器
public void publishEvent(ApplicationEvent event) {
publishEvent(event, null);
}//重载
protected void publishEvent(Object event, ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
if (logger.isTraceEnabled()) { logger.trace("Publishing event in " + getDisplayName() + ": " + event); }
// Decorate event as an ApplicationEvent if necessary
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
applicationEvent = new PayloadApplicationEvent<Object>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
}
}
// Multicast right now if possible - or lazily once the multicaster is initialized
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
// ***获取到应用事件的派发器(多播器),即把这个事件发送给多个监听器让他们感知//然后调用multicastEvent方法 派发事件
getApplicationEventMulticaster().//(1) 获取多播器
multicastEvent(applicationEvent, eventType);//(2) 派发事件
}
// 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);
}
}
}
(3)multicastEvent
- 找到监听器getApplicationListeners(event, type)
- 给监听器发送事件invokeListener(listener, event);
public class SimpleApplicationEventMulticaster
extends AbstractApplicationEventMulticaster {
@Nullable
private Executor taskExecutor;
@Nullable
private ErrorHandler errorHandler;
@Override//派发事件
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
// 遍历容器监听器
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();//如果有executor,可以利用executor进行异步执行的话
// 可以用多线程方式异步派发事件
if (executor != null) {
// 类似于线程池
executor.execute(new Runnable() {
@Override
public void run() {
invokeListener(listener, event);//也是执行方法
}
});
}
else {//同步 方式直接执行方法
invokeListener(listener, event);
}
}
}
(4)getApplicationListeners()
public abstract class AbstractApplicationEventMulticaster
implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);
final Map<ListenerCacheKey, ListenerRetriever> retrieverCache = new ConcurrentHashMap<>(64);
@Nullable
private ClassLoader beanClassLoader;
@Nullable
private ConfigurableBeanFactory beanFactory;
private Object retrievalMutex = this.defaultRetriever;
protected Collection<ApplicationListener<?>> getApplicationListeners(
ApplicationEvent event, ResolvableType eventType) {
Object source = event.getSource();
Class<?> sourceType = (source != null ? source.getClass() : null);
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
// Quick check for existing entry on ConcurrentHashMap...
ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
}
if (this.beanClassLoader == null ||
(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
// Fully synchronized building and caching of a ListenerRetriever
synchronized (this.retrievalMutex) {
retriever = this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
}
retriever = new ListenerRetriever(true);
Collection<ApplicationListener<?>> listeners =
retrieveApplicationListeners(eventType, sourceType, retriever);
this.retrieverCache.put(cacheKey, retriever);
return listeners;
}
}
else {
// No ListenerRetriever caching -> no synchronization necessary
return retrieveApplicationListeners(eventType, sourceType, null);
}
}
(5)invokeListener
// SimpleApplicationEventMulticaster;
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);//
}
}
doInvokeListener
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
// 拿到容器对象后回调 //如果我们自定义的逻辑,重写的就是onApplicationEvent方法,获得ac.close()里也有
listener.onApplicationEvent(event);//回调
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || msg.startsWith(event.getClass().getName())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
Log logger = LogFactory.getLog(getClass());
}
else {
throw ex;
}
}
}
四、initApplicationEventMulticaster
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
...;
try {
,,,;
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();// 初始化事件多播器
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();//注册监听器
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 先去容器中找
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {//"applicationEventMulticaster";
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
// 如果没有多播器就new一个
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() + "]");
}
}
}
五、registerListeners();
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
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类型的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;
if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
六、注册监听方式
// 也可以@EventListener
@Service
public class UserService {
@EventListener(classes={ApplicationEvent.class})//原理:使用EventListenerMethodProcessor处理器解析方法上的@EventListener // 可以看EventListenerMethodProcessor
public void listen(ApplicationEvent event){
System.out.println("UserService。。监听到的事件:"+event);
}
}
/*
* @see EventListenerMethodProcessor
*/
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EventListener {
EventListenerMethodProcessor
public class EventListenerMethodProcessor
implements SmartInitializingSingleton, //
ApplicationContextAware,
BeanFactoryPostProcessor {
public interface SmartInitializingSingleton {
/**
所有单实例bean已经创建完成
* Invoked right at the end of the singleton pre-instantiation phase,
* with a guarantee that all regular singleton beans have been created
* already. {@link ListableBeanFactory#getBeansOfType} calls within
* this method won't trigger accidental side effects during bootstrap.
* <p><b>NOTE:</b> This callback won't be triggered for singleton beans
* lazily initialized on demand after {@link BeanFactory} bootstrap,
* and not for any other bean scope either. Carefully use it for beans
* with the intended bootstrap semantics only.
*/
void afterSingletonsInstantiated();
}
SmartInitializingSingleton原理:
refresh
在finish实例化单实例bean
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);
// 实例化单实例eban
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
...;
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
...;
}
// 实例化完了,
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
// 拿到实例化完的bean
Object singletonInstance = getSingleton(beanName);
// 判断是否是SmartInitializingSingleton,
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();// 这里
}
}
}
}
public class EventListenerMethodProcessor
implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {
@Override
public void afterSingletonsInstantiated() {
ConfigurableListableBeanFactory beanFactory = this.beanFactory;
Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
for (String beanName : beanNames) {
if (!ScopedProxyUtils.isScopedTarget(beanName)) {
Class<?> type = null;
try {
type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
}
}
if (type != null) {
if (ScopedObject.class.isAssignableFrom(type)) {
try {
Class<?> targetClass = AutoProxyUtils.determineTargetClass(
beanFactory, ScopedProxyUtils.getTargetBeanName(beanName));
if (targetClass != null) {
type = targetClass;
}
}
catch (Throwable ex) {
// An invalid scoped proxy arrangement - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target bean for scoped proxy '" + beanName + "'", ex);
}
}
}
try {
processBean(beanName, type);
}
catch (Throwable ex) {
throw new BeanInitializationException("Failed to process @EventListener " +
"annotation on bean with name '" + beanName + "'", ex);
}
}
}
}
}