Spring is the core ApplicationContext , which is responsible for managing the complete lifecycle of Bean; when loading Bean, ApplicationContext to publish certain types of events; for example, when the context start, ContextStartedEvent announced, when the context is stopped, ContextStoppedEvent news release;
Interface to provide event handling in the ApplicationContext class and by ApplicationEvent ApplicationListener; if a Bean implementation ApplicationListener interface, each ApplicationEvent be published to the ApplicationContext, the Bean instance will be notified; similar MQ publish-subscribe;
ApplicationEvent UML diagram is as follows:
-
Spring Common events
No. | Spring Event |
---|---|
1 | ContextRefreshedEvent: when the ApplicationContext is initialized or refreshed, the event is released; it can also occur using the refresh () method in ConfigurableApplicationContext interface; container refresh is complete (all bean are created entirely) will be released this event; |
2 | ContextStartedEvent: When ConfigurableApplicationContext interface start () method to start ApplicationContext, the event is released; |
3 | ContextStoppedEvent: When ConfigurableApplicationContext interface stop () method to stop ApplicationContext, released this event; |
4 | ContextClosedEvent: When ConfigurableApplicationContext interface close () method to close ApplicationContext, the event is released; |
5 | RequestHandledEvent: In Web applications, when the end of a http request triggers the event |
-
ApplicationContext
That ApplicationContext application context inherited from the BeanFactory interface can be used to obtain Bean Spring managed object instances;
ApplicationContextAware: Aware property is injected, and the ApplicationContextAware ApplicationContext difference is, when initialization Spring container, realized Bean ApplicationContextAware interface automatically injected ApplicationContext;
Custom ApplicationContextAware
@Component public class ApplicationContextProvider implements ApplicationContextAware { private ApplicationContext applicationContext; /** * Context instances * @param applicationContext * @throws BeansException */ @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } /** * Get context * @return */ public ApplicationContext getApplicationContext() { return this.applicationContext; } /** * Get Bean instances by class name * @param name * @return */ public Object getBean(String name) { return this.applicationContext.getBean(name); } /** * Get Bean instance bytecode * @Param clazz * @param <T> * @return */ public <T> T getBean(Class<T> clazz) { return this.applicationContext.getBean(clazz); } }
-
ApplicationListener
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { /** * Handle an application event. * @param event the event to respond to */ void onApplicationEvent(E event); }
AbstractApplicationContext.java
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext { ... }
ConfigurableApplicationContext: SPI interfaces implemented by most application context; in addition to providing a method of client application context, the configuration also provides the application context ApplicationContext interface functionality;
refresh method to execute loading the container
public void refresh() throws BeansException, IllegalStateException { ... // Initialize event multicaster for this context. initApplicationEventMulticaster(); ... // Last step: publish corresponding event. finishRefresh(); ... } protected void initApplicationEventMulticaster() { ConfigurableListableBeanFactory beanFactory = getBeanFactory(); // find out whether there is "applicationEventMulticaster" component container 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 { // not the new "applicationEventMulticaster" components, and added to the vessel, is injected into the "applicationEventMulticaster", registerSingleton looks listener's existence within all registered listeners map, there is no operation is performed to put the map 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 + "]"); } } }
finshRefresh method
protected void finishRefresh() { // Clear context-level resource caches (such as ASM metadata from scanning). clearResourceCaches(); // Initialize lifecycle processor for this context. initLifecycleProcessor(); // Propagate refresh to lifecycle processor first. getLifecycleProcessor().onRefresh(); // Publish the final event. publishEvent(new ContextRefreshedEvent(this)); // Participate in LiveBeansView MBean, if active. LiveBeansView.registerApplicationContext(this); }
publishEvent way to publish events
@Override public void publishEvent(ApplicationEvent event) { publishEvent(event, null); } protected void publishEvent(Object event, @Nullable 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<>(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... // determine the current ApplicationContext there is no parent ApplicationContext if (this.parent != null) { if (this.parent instanceof AbstractApplicationContext) { ((AbstractApplicationContext) this.parent).publishEvent(event, eventType); } else { this.parent.publishEvent(event); } } }
AbstractApplicationEventMulticaster provide basic listener registration function
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster { }
SimpleApplicationEventMulticaster.java
// given application is distributed to the corresponding event listener @Override 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); } } } // call the given event listener 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 { onApplicationEvent // method call implementation ApplicationListener interface 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; } } }