四时宝库

程序员的知识宝库

(原创)Spring步步通第二步----Starting事件

在第一步里,我们主要对Spring的类载入过程做了跟进解读,并对run方法体做了展示。本篇重点就来解读Staring事件。

在第一步SpringApplication.run方法里的

SpringApplicationRunListeners listeners = getRunListeners(args);

listeners.starting();

这两行代码即是Staring事件调用。

private SpringApplicationRunListeners getRunListeners(String[] args) {

Class[] types = new Class[] { SpringApplication.class, String[].class };

return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(

SpringApplicationRunListener.class, types, this, args));

}

从第一步里我们其实认识了一个重要的方法getSpringFactoriesInstances , 即spring的实例工厂,其原理是:通过类名反射生产出类实例。这里将实现SpringApplicationRunListener 接口的类的通过Spring工厂实例后集合封装在SpringApplicationRunListeners实例的listeners字段中。而实现SpringApplicationRunListener 接口的类一般就是EventPublishingRunListener这个类,即listeners中将包含EventPublishingRunListener实例。

然后,触发listeners的staring事件,即遍历每个SpringApplicationRunListener的类的staring事件,就是EventPublishingRunListener的staring事件。

class SpringApplicationRunListeners {

private final Log log;

private final List listeners;

SpringApplicationRunListeners(Log log,

Collectionextends SpringApplicationRunListener> listeners) {

this.log = log;

this.listeners = new ArrayList<>(listeners);

}

public void starting() {

for (SpringApplicationRunListener listener : this.listeners) {

listener.starting();

}

}

………………………………..

}

上面我们讲到EventPublishingRunListener实例是被Spring工厂生产出来的,而该实例中包含了一个重要字段initialMulticaster(= new SimpleApplicationEventMulticaster),需要强调的是在构建EventPublishingRunListener实例时,会将application.listeners集合传给initialMulticaster. defaultRetriever.applicationListeners,(这些都是事件侦听器,为事件滚轮执行做准备). 详见EventPublishingRunListener的构造方法,defaultRetriever是默认的ListenerRetriever实例,其preFiltered=false,表示未被检索过滤的ListenerRetriever。

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);

}

}

@Override

public int getOrder() {

return 0;

}

@Override

public void starting() {

this.initialMulticaster.multicastEvent(

new ApplicationStartingEvent(this.application, this.args));

}

…………………

}

public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {

@Nullable

private Executor taskExecutor;

@Nullable

private ErrorHandler errorHandler;

/**

* Create a new SimpleApplicationEventMulticaster.

*/

public SimpleApplicationEventMulticaster() {

}

/**

* Create a new SimpleApplicationEventMulticaster for the given BeanFactory.

*/

public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {

setBeanFactory(beanFactory);

}

/**

* Set a custom executor (typically a {@link org.springframework.core.task.TaskExecutor})

* to invoke each listener with.

*

Default is equivalent to {@link org.springframework.core.task.SyncTaskExecutor},

* executing all listeners synchronously in the calling thread.

*

Consider specifying an asynchronous task executor here to not block the

* caller until all listeners have been executed. However, note that asynchronous

* execution will not participate in the caller's thread context (class loader,

* transaction association) unless the TaskExecutor explicitly supports this.

* @see org.springframework.core.task.SyncTaskExecutor

* @see org.springframework.core.task.SimpleAsyncTaskExecutor

*/

public void setTaskExecutor(@Nullable Executor taskExecutor) {

this.taskExecutor = taskExecutor;

}

/**

* Return the current task executor for this multicaster.

*/

@Nullable

protected Executor getTaskExecutor() {

return this.taskExecutor;

}

/**

* Set the {@link ErrorHandler} to invoke in case an exception is thrown

* from a listener.

*

Default is none, with a listener exception stopping the current

* multicast and getting propagated to the publisher of the current event.

* If a {@linkplain #setTaskExecutor task executor} is specified, each

* individual listener exception will get propagated to the executor but

* won't necessarily stop execution of other listeners.

*

Consider setting an {@link ErrorHandler} implementation that catches

* and logs exceptions (a la

* {@link org.springframework.scheduling.support.TaskUtils#LOG_AND_SUPPRESS_ERROR_HANDLER})

* or an implementation that logs exceptions while nevertheless propagating them

* (e.g. {@link org.springframework.scheduling.support.TaskUtils#LOG_AND_PROPAGATE_ERROR_HANDLER}).

* @since 4.1

*/

public void setErrorHandler(@Nullable ErrorHandler errorHandler) {

this.errorHandler = errorHandler;

}

/**

* Return the current error handler for this multicaster.

* @since 4.1

*/

@Nullable

protected ErrorHandler getErrorHandler() {

return this.errorHandler;

}

@Override

public void multicastEvent(ApplicationEvent event) {

multicastEvent(event, resolveDefaultEventType(event));

}

@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);

}

}

}

private ResolvableType resolveDefaultEventType(ApplicationEvent event) {

return ResolvableType.forInstance(event);

}

/**

* Invoke the given listener with the given event.

* @param listener the ApplicationListener to invoke

* @param event the current event to propagate

* @since 4.1

*/

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);

}

}

@SuppressWarnings({"unchecked", "rawtypes"})

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;

}

}

}

private boolean matchesClassCastMessage(String classCastMessage, Class eventClass) {

// On Java 8, the message starts with the class name: "java.lang.String cannot be cast..."

if (classCastMessage.startsWith(eventClass.getName())) {

return true;

}

// On Java 11, the message starts with "class ..." a.k.a. Class.toString()

if (classCastMessage.startsWith(eventClass.toString())) {

return true;

}

// On Java 9, the message used to contain the module name: "java.base/java.lang.String cannot be cast..."

int moduleSeparatorIndex = classCastMessage.indexOf('/');

if (moduleSeparatorIndex != -1 && classCastMessage.startsWith(eventClass.getName(), moduleSeparatorIndex + 1)) {

return true;

}

// Assuming an unrelated class cast failure...

return false;

}

}

接下来,我们再来看下EventPublishingRunListener类的staring方法,该方法主要是在传递事件,一直传递到了SimpleApplicationEventMulticaster。因为EventPublishingRunListener实现的是SpringApplicationRunListener接口,而SpringApplicationRunListeners类是SpringApplicationRunListener的集合封装类,因此在形式上和SpringApplicationRunListeners很像,即事件侦听器集合和事件侦听器的关系。而SimpleApplicationEventMulticaster是事件滚轮,SimpleApplicationEventMulticaster是事件的执行器,而其方法multicastEvent是执行方法。

执行步骤如下:

1. 检索原defaultRetriever中的applicationListeners过滤后到新Retriever的applicatioListeners并缓存,(具体过滤流程见下面解读)

2. 执行invokeListener

public abstract class AbstractApplicationEventMulticaster

implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {

private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);

final Map retrieverCache = new ConcurrentHashMap<>(64);

@Nullable

private ClassLoader beanClassLoader;

@Nullable

private BeanFactory beanFactory;

private Object retrievalMutex = this.defaultRetriever;

@Override

public void setBeanClassLoader(ClassLoader classLoader) {

this.beanClassLoader = classLoader;

}

@Override

public void setBeanFactory(BeanFactory beanFactory) {

this.beanFactory = beanFactory;

if (beanFactory instanceof ConfigurableBeanFactory) {

ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) beanFactory;

if (this.beanClassLoader == null) {

this.beanClassLoader = cbf.getBeanClassLoader();

}

this.retrievalMutex = cbf.getSingletonMutex();

}

}

private BeanFactory getBeanFactory() {

if (this.beanFactory == null) {

throw new IllegalStateException("ApplicationEventMulticaster cannot retrieve listener beans " +

"because it is not associated with a BeanFactory");

}

return this.beanFactory;

}

@Override

public void addApplicationListener(ApplicationListener listener) {

synchronized (this.retrievalMutex) {

// Explicitly remove target for a proxy, if registered already,

// in order to avoid double invocations of the same listener.

Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);

if (singletonTarget instanceof ApplicationListener) {

this.defaultRetriever.applicationListeners.remove(singletonTarget);

}

this.defaultRetriever.applicationListeners.add(listener);

this.retrieverCache.clear();

}

}

@Override

public void addApplicationListenerBean(String listenerBeanName) {

synchronized (this.retrievalMutex) {

this.defaultRetriever.applicationListenerBeans.add(listenerBeanName);

this.retrieverCache.clear();

}

}

@Override

public void removeApplicationListener(ApplicationListener listener) {

synchronized (this.retrievalMutex) {

this.defaultRetriever.applicationListeners.remove(listener);

this.retrieverCache.clear();

}

}

@Override

public void removeApplicationListenerBean(String listenerBeanName) {

synchronized (this.retrievalMutex) {

this.defaultRetriever.applicationListenerBeans.remove(listenerBeanName);

this.retrieverCache.clear();

}

}

@Override

public void removeAllListeners() {

synchronized (this.retrievalMutex) {

this.defaultRetriever.applicationListeners.clear();

this.defaultRetriever.applicationListenerBeans.clear();

this.retrieverCache.clear();

}

}

/**

* Return a Collection containing all ApplicationListeners.

* @return a Collection of ApplicationListeners

* @see org.springframework.context.ApplicationListener

*/

protected Collection> getApplicationListeners() {

synchronized (this.retrievalMutex) {

return this.defaultRetriever.getApplicationListeners();

}

}

/**

* Return a Collection of ApplicationListeners matching the given

* event type. Non-matching listeners get excluded early.

* @param event the event to be propagated. Allows for excluding

* non-matching listeners early, based on cached matching information.

* @param eventType the event type

* @return a Collection of ApplicationListeners

* @see org.springframework.context.ApplicationListener

*/

protected Collection> 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> listeners =

retrieveApplicationListeners(eventType, sourceType, retriever);

this.retrieverCache.put(cacheKey, retriever);

return listeners;

}

}

else {

// No ListenerRetriever caching -> no synchronization necessary

return retrieveApplicationListeners(eventType, sourceType, null);

}

}

/**

* Actually retrieve the application listeners for the given event and source type.

* @param eventType the event type

* @param sourceType the event source type

* @param retriever the ListenerRetriever, if supposed to populate one (for caching purposes)

* @return the pre-filtered list of application listeners for the given event and source type

*/

private Collection> retrieveApplicationListeners(

ResolvableType eventType, @Nullable Class sourceType, @Nullable ListenerRetriever retriever) {

List> allListeners = new ArrayList<>();

Set> listeners;

Set listenerBeans;

synchronized (this.retrievalMutex) {

listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);

listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);

}

for (ApplicationListener listener : listeners) {

if (supportsEvent(listener, eventType, sourceType)) {

if (retriever != null) {

retriever.applicationListeners.add(listener);

}

allListeners.add(listener);

}

}

if (!listenerBeans.isEmpty()) {

BeanFactory beanFactory = getBeanFactory();

for (String listenerBeanName : listenerBeans) {

try {

Class listenerType = beanFactory.getType(listenerBeanName);

if (listenerType == null || supportsEvent(listenerType, eventType)) {

ApplicationListener listener =

beanFactory.getBean(listenerBeanName, ApplicationListener.class);

if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {

if (retriever != null) {

if (beanFactory.isSingleton(listenerBeanName)) {

retriever.applicationListeners.add(listener);

}

else {

retriever.applicationListenerBeans.add(listenerBeanName);

}

}

allListeners.add(listener);

}

}

}

catch (NoSuchBeanDefinitionException ex) {

// Singleton listener instance (without backing bean definition) disappeared -

// probably in the middle of the destruction phase

}

}

}

AnnotationAwareOrderComparator.sort(allListeners);

if (retriever != null && retriever.applicationListenerBeans.isEmpty()) {

retriever.applicationListeners.clear();

retriever.applicationListeners.addAll(allListeners);

}

return allListeners;

}

/**

* Filter a listener early through checking its generically declared event

* type before trying to instantiate it.

*

If this method returns {@code true} for a given listener as a first pass,

* the listener instance will get retrieved and fully evaluated through a

* {@link #supportsEvent(ApplicationListener,ResolvableType, Class)} call afterwards.

* @param listenerType the listener's type as determined by the BeanFactory

* @param eventType the event type to check

* @return whether the given listener should be included in the candidates

* for the given event type

*/

protected boolean supportsEvent(Class listenerType, ResolvableType eventType) {

if (GenericApplicationListener.class.isAssignableFrom(listenerType) ||

SmartApplicationListener.class.isAssignableFrom(listenerType)) {

return true;

}

ResolvableType declaredEventType = GenericApplicationListenerAdapter.resolveDeclaredEventType(listenerType);

return (declaredEventType == null || declaredEventType.isAssignableFrom(eventType));

}

/**

* Determine whether the given listener supports the given event.

*

The default implementation detects the {@link SmartApplicationListener}

* and {@link GenericApplicationListener} interfaces. In case of a standard

* {@link ApplicationListener}, a {@link GenericApplicationListenerAdapter}

* will be used to introspect the generically declared type of the target listener.

* @param listener the target listener to check

* @param eventType the event type to check against

* @param sourceType the source type to check against

* @return whether the given listener should be included in the candidates

* for the given event type

*/

protected boolean supportsEvent(

ApplicationListener listener, ResolvableType eventType, @Nullable Class sourceType) {

GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?

(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));

return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));

}

/**

* Cache key for ListenerRetrievers, based on event type and source type.

*/

private static final class ListenerCacheKey implements Comparable {

private final ResolvableType eventType;

@Nullable

private final Class sourceType;

public ListenerCacheKey(ResolvableType eventType, @Nullable Class sourceType) {

Assert.notNull(eventType, "Event type must not be null");

this.eventType = eventType;

this.sourceType = sourceType;

}

@Override

public boolean equals(Object other) {

if (this == other) {

return true;

}

ListenerCacheKey otherKey = (ListenerCacheKey) other;

return (this.eventType.equals(otherKey.eventType) &&

ObjectUtils.nullSafeEquals(this.sourceType, otherKey.sourceType));

}

@Override

public int hashCode() {

return this.eventType.hashCode() * 29 + ObjectUtils.nullSafeHashCode(this.sourceType);

}

@Override

public String toString() {

return "ListenerCacheKey [eventType = " + this.eventType + ", sourceType = " + this.sourceType + "]";

}

@Override

public int compareTo(ListenerCacheKey other) {

int result = this.eventType.toString().compareTo(other.eventType.toString());

if (result == 0) {

if (this.sourceType == null) {

return (other.sourceType == null ? 0 : -1);

}

if (other.sourceType == null) {

return 1;

}

result = this.sourceType.getName().compareTo(other.sourceType.getName());

}

return result;

}

}

/**

* Helper class that encapsulates a specific set of target listeners,

* allowing for efficient retrieval of pre-filtered listeners.

*

An instance of this helper gets cached per event type and source type.

*/

private class ListenerRetriever {

public final Set> applicationListeners = new LinkedHashSet<>();

public final Set applicationListenerBeans = new LinkedHashSet<>();

private final boolean preFiltered;

public ListenerRetriever(boolean preFiltered) {

this.preFiltered = preFiltered;

}

public Collection> getApplicationListeners() {

List> allListeners = new ArrayList<>(

this.applicationListeners.size() + this.applicationListenerBeans.size());

allListeners.addAll(this.applicationListeners);

if (!this.applicationListenerBeans.isEmpty()) {

BeanFactory beanFactory = getBeanFactory();

for (String listenerBeanName : this.applicationListenerBeans) {

try {

ApplicationListener listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class);

if (this.preFiltered || !allListeners.contains(listener)) {

allListeners.add(listener);

}

}

catch (NoSuchBeanDefinitionException ex) {

// Singleton listener instance (without backing bean definition) disappeared -

// probably in the middle of the destruction phase

}

}

}

if (!this.preFiltered || !this.applicationListenerBeans.isEmpty()) {

AnnotationAwareOrderComparator.sort(allListeners);

}

return allListeners;

}

}

}

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言
    友情链接