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机制的主要内容,如果未能解决你的问题,请参考以下文章

ApplicationListener机制

ApplicationListener机制

Spring中ApplicationListener的使用

Spring中ApplicationListener的使用

ApplicationListener的使用

设计模式之-观察者模式