ApplicationListener机制
Posted 恒奇恒毅
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ApplicationListener机制相关的知识,希望对你有一定的参考价值。
ApplicationListener机制
ApplicationListener机制是Sprint提供的用于实现发布订阅功能的机制,也是观察者模式的典型实现。程序中事先注册ApplicationListener
,当某些事件发生的时候通过调用ApplicationListener
#onApplicationEvent就可以实现发布订阅功能。
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener
/**
* Handle an application event.
* @param event the event to respond to
*/
void onApplicationEvent(E event);
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;
/**
* Create a new ApplicationEvent.
* @param source the object on which the event initially occurred (never @code null)
*/
public ApplicationEvent(Object source)
super(source);
this.timestamp = System.currentTimeMillis();
/**
* Return the system time in milliseconds when the event happened.
*/
public final long getTimestamp()
return this.timestamp;
在这个过程中发送器就很重要了,相当于一个中转站,而在Spring中完成这个功能的类是:SimpleApplicationEventMulticaster
,他通过线程池技术实现了同步和异步执行两种方式。
该类实现了ApplicationEventMulticaster
,提供注册监听器ApplicationListener
和广播事件的方法multicastEvent,multicastEvent方法中从BeanFactory中获取ApplicationListener进行调用。
public interface ApplicationEventMulticaster
/**
* Add a listener to be notified of all events.
* @param listener the listener to add
*/
void addApplicationListener(ApplicationListener<?> listener);
/**
* Add a listener bean to be notified of all events.
* @param listenerBeanName the name of the listener bean to add
*/
void addApplicationListenerBean(String listenerBeanName);
/**
* Remove a listener from the notification list.
* @param listener the listener to remove
*/
void removeApplicationListener(ApplicationListener<?> listener);
/**
* Remove a listener bean from the notification list.
* @param listenerBeanName the name of the listener bean to add
*/
void removeApplicationListenerBean(String listenerBeanName);
/**
* Remove all listeners registered with this multicaster.
* <p>After a remove call, the multicaster will perform no action
* on event notification until new listeners are being registered.
*/
void removeAllListeners();
/**
* Multicast the given application event to appropriate listeners.
* <p>Consider using @link #multicastEvent(ApplicationEvent, ResolvableType)
* if possible as it provides a better support for generics-based events.
* @param event the event to multicast
*/
void multicastEvent(ApplicationEvent event);
/**
* Multicast the given application event to appropriate listeners.
* <p>If the @code eventType is @code null, a default type is built
* based on the @code event instance.
* @param event the event to multicast
* @param eventType the type of event (can be null)
* @since 4.2
*/
void multicastEvent(ApplicationEvent event, ResolvableType eventType);
SimpleApplicationEventMulticaster在什么地方初始化和使用?
在Spring的ApplicationContext的refresh方法中对ApplicationEventMulticaster进行了初始化
@Override
public void refresh() throws BeansException, IllegalStateException
synchronized (this.startupShutdownMonitor)
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
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();
catch (BeansException ex)
if (logger.isWarnEnabled())
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
finally
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
protected void initApplicationEventMulticaster()
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME))
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isDebugEnabled())
logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
else
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isDebugEnabled())
logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
"': using default [" + this.applicationEventMulticaster + "]");
如果我们没有自定义ApplicationEventMulticaster,那么系统就使用默认的SimpleApplicationEventMulticaster。
ApplicationEventPublisher 提供了发送事件的方法,而ApplicationContext继承自此接口,所以我们在应用中通过ApplicationContext#publishEvent方法即可发布事件。
public interface ApplicationEventPublisher
/**
* Notify all <strong>matching</strong> listeners registered with this
* application of an application event. Events may be framework events
* (such as RequestHandledEvent) or application-specific events.
* @param event the event to publish
* @see org.springframework.web.context.support.RequestHandledEvent
*/
void publishEvent(ApplicationEvent event);
/**
* Notify all <strong>matching</strong> listeners registered with this
* application of an event.
* <p>If the specified @code event is not an @link ApplicationEvent,
* it is wrapped in a @link PayloadApplicationEvent.
* @param event the event to publish
* @since 4.2
* @see PayloadApplicationEvent
*/
void publishEvent(Object event);
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
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);
SpringBoot中对ApplicationListener机制的使用
public interface SpringApplicationRunListener
/**
* Called immediately when the run method has first started. Can be used for very
* early initialization.
*/
void starting();
/**
* Called once the environment has been prepared, but before the
* @link ApplicationContext has been created.
* @param environment the environment
*/
void environmentPrepared(ConfigurableEnvironment environment);
/**
* Called once the @link ApplicationContext has been created and prepared, but
* before sources have been loaded.
* @param context the application context
*/
void contextPrepared(ConfigurableApplicationContext context);
/**
* Called once the application context has been loaded but before it has been
* refreshed.
* @param context the application context
*/
void contextLoaded(ConfigurableApplicationContext context);
/**
* Called immediately before the run method finishes.
* @param context the application context or null if a failure occurred before the
* context was created
* @param exception any run exception or null if run completed successfully.
*/
void finished(ConfigurableApplicationContext context, Throwable exception);
SpringApplicationRunListener
定义了应用运行各个时机的方法,其实现类EventPublishingRunListener
使用的广播器就是SimpleApplicationEventMulticaster,他的ApplicationListener
来自SpringApplication
初始化中通过spring.factories机制获取的。EventPublishingRunListener也是采用spring.factories机制注册。然后在SpringApplication
中获取,再通过SpringApplicationRunListeners
包装
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered
private final SpringApplication application;
private final String[] args;
private final SimpleApplicationEventMulticaster initialMulticaster;
public EventPublishingRunListener(SpringApplication application, String[] args)
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
for (ApplicationListener<?> listener : application.getListeners())
this.initialMulticaster.addApplicationListener(listener);
private void initialize(Object[] sources)
if (sources != null && sources.length > 0)
this.sources.addAll(Arrays.asList(sources));
this.webEnvironment = deduceWebEnvironment();
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
private SpringApplicationRunListeners getRunListeners(String[] args)
Class<?>[] types = new Class<?>[] SpringApplication.class, String[].class ;
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
然后在各个时机进行调用
public ConfigurableApplicationContext run(String... args)
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo)
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
return context;
catch (Throwable ex)
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
以上是关于ApplicationListener机制的主要内容,如果未能解决你的问题,请参考以下文章