Как Spring реализует механизм мониторинга событий? Исходный код Spring (2)

Spring

Примечание. Анализ соответствующей версии исходного кода spring5.1.x

1 Обзор

В этой статье начинается анализ исходного кода механизма событий Spring, поскольку механизм событий Spring по сути является реализацией режима наблюдателя (публикации и подписки), поэтому, если вы хотите понять механизм событий Spring, вы должны знать, что такое режим наблюдателя.

в то же время,Затем в этой статье имитируется механизм событий Spring для реализации пользовательского программирования, управляемого событиями — анализ исходного кода механизма событий Spring (1).В этой статье после реализации простой демонстрации событийно-управляемого программирования гораздо проще проанализировать исходный код механизма событий Spring в настоящее время.

Прежде чем приступить к теме, давайте поговорим об ощущениях от исследования исходного кода: прежде чем исследовать исходный код, вы должны сначала понять взаимосвязь между классами и классами, например, какие классы реализации имеет интерфейс, какие подклассы есть у родительского класса и связь между подклассами и классами Связь между подклассами и связь между этими классами понятна, поэтому гораздо проще приступить к изучению исходного кода. Короче говоря, вы не можете сразу ввести определенную деталь исходного кода, что приведет к тому, что вы увидите только верхушку айсберга, а не всю картину.

Что ж, давайте перейдем к делу и начнем изучать механизм событий Spring. Поскольку программирование обычно представляет собой программирование, ориентированное на интерфейс, мы начинаем с анализа соответствующего интерфейса или абстрактного класса механизма событий.

Важные классы, участвующие в механизме событий Spring, в основном включают следующие четыре:

  • ApplicationEvent: Event, этот абстрактный класс является родительским классом для всех событий Spring и может содержать такие данные, как временная метка времени возникновения события.
  • ApplicationListener: прослушиватель событий, этот интерфейс реализуется всеми прослушивателями событий на основе стандартного интерфейса java EventListener для реализации режима наблюдателя.
  • ApplicationEventMulticaster: диспетчер событий, управляет слушателями и публикует события, ApplicationContext публикует события, делегируя ApplicationEventMulticaster.
  • ApplicationEventPublisher: издатель событий, этот интерфейс инкапсулирует общедоступные методы, связанные с событием. Как профиль супер-улицы ApplicationContext, он также поручает ApplicationEventMulticaster завершить публикацию события.

2. Весенние события включают анализ исходного кода класса

Введен основной класс интерфейса события, а связь между каждым интерфейсом и его подкатегорией показана ниже.

2.1 ApplicationEvent

Сначала посмотрите на диаграмму классов следующим образом:

Рисунок 1

Его интерфейсный код выглядит следующим образом:

// 事件抽象类,这个是所有Spring事件的父类
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;
	}

}

Класс ApplicationEvent определяет некоторые свойства, такие как метка времени, которые представляют время возникновения события, поэтому некоторые параметры могут быть переданы через событие.

На рисунке 1 показана важная диаграмма отношений подклассов части ApplicationEvent. Наиболее важным подклассом ApplicationEvent является абстрактный класс ApplicationContextEvent. ApplicationContextEvent — это базовый класс событий жизненного цикла контекста контейнера Spring. Существует четыре подкласса ApplicationContextEvent, а именно:

  • Contextrefreshedevent: срабатывает, когда весной контекст контекста обновляется
  • ContextStartedEvent: срабатывает при запуске контекста контейнера Spring.
  • ContextStoppedEvent: срабатывает, когда контекст контейнера Spring останавливается.
  • ContextClosedEvent: срабатывает, когда контекст контейнера Spring закрывается, а когда контейнер закрывается, все одноэлементные компоненты, управляемые им, уничтожаются.

Вышеупомянутые четыре события - это четыре события жизненного цикла контейнера Spring. Когда каждое событие запускается, соответствующий слушатель будет прослушивать соответствующее событие, а затем запускать метод onApplicationEvent. В это время могут быть созданы некоторые контейнеры. В то же время эти события контейнера следуют за ними. Как и постпроцессор Spring, пользователю остается расширять пользовательскую логику в виде открытой точки расширения.

Возьмите событие ContextRefreshedEvent в качестве примера, чтобы объяснить соответствующие классы прослушивания.Благодаря глобальному поиску по ключевому слову "(ContextRefreshedEvent" в идее получаются следующие снимки экрана:

На карте вы можете увидеть модуль Spring-webmvc FrameworkServlet, модуль Spring-Context ScheduledAnnotationBeanPostProcessor и модуль Spring-JMS JmsListenerEndpointRegistry, подписанный на ContextRefreshedEvent и другие типы событий, поэтому при обновлении судна эти классы будут прослушивать событие ContextRefreshedEvent, выполняя некоторую логику инициализации. За этим было время учиться, TODO.

Вставьте приведенные ниже коды реализации четырех подклассов ApplicationContextEvent, которые в основном наследуют родительский класс ApplicationContextEvent без какой-либо логики и являются скорее классом знаков для событий жизненного цикла.

public class ContextRefreshedEvent extends ApplicationContextEvent {

	// 当springcontext已经被初始化或者刷新的时候,创建该事件
	public ContextRefreshedEvent(ApplicationContext source) {
		super(source);
	}

}

public class ContextStartedEvent extends ApplicationContextEvent {

	// 当springContext已经启动的时候,创建该事件
	public ContextStartedEvent(ApplicationContext source) {
		super(source);
	}

}

public class ContextStoppedEvent extends ApplicationContextEvent {

	// 当springContext已经停止时创建该事件
	public ContextStoppedEvent(ApplicationContext source) {
		super(source);
	}

}

public class ContextClosedEvent extends ApplicationContextEvent {

	// 当springContext关闭时创建该事件
	public ContextClosedEvent(ApplicationContext source) {
		super(source);
	}

}

2.2 ApplicationListener

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

	/**
	 * Handle an application event.
	 * @param event the event to respond to
	 */
	void onApplicationEvent(E event);

}

ApplicationListener — это родительский интерфейс всех прослушивателей событий, и прослушиватели событий должны реализовать этот интерфейс для прослушивания события. Здесь стоит отметить параметризованный тип интерфейса ApplicationListener. В этом случае конкретный слушатель может указать конкретный класс события при реализации интерфейса. Когда входящее событие не является конкретным событием, когда оно направлено вниз, оно будет генерировать класс исключение конверсии. Однако при обычном использовании он сначала определяет, принадлежит ли тип события к определенному событию, а затем выполняет соответствующую логику следующим образом:

    @Override
	public void onApplicationEvent(ApplicationEvent event) {
		if (event instanceof ApplicationStartingEvent) {
			onApplicationStartingEvent((ApplicationStartingEvent) event);
		}
		else if (event instanceof ApplicationEnvironmentPreparedEvent) {
			onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
		}
		else if (event instanceof ApplicationPreparedEvent) {
			onApplicationPreparedEvent((ApplicationPreparedEvent) event);
		}
		else if (event instanceof ContextClosedEvent
				&& ((ContextClosedEvent) event).getApplicationContext().getParent() == null) {
			onContextClosedEvent();
		}
		else if (event instanceof ApplicationFailedEvent) {
			onApplicationFailedEvent();
		}
	}

Поскольку существует слишком много конкретных классов реализации интерфейса ApplicationListener, диаграмма классов не публикуется.

2.3 ApplicationEventMulticaster

Сначала посмотрите на диаграмму классов,

Интерфейсная функция ApplicationEventMulticaster в основном используется для трансляции событий всем слушателям.Она в основном определяет методы интерфейса для добавления, удаления и изменения слушателей и трансляции событий.Код выглядит следующим образом:

public interface ApplicationEventMulticaster {
    void addApplicationListener(ApplicationListener<?> var1);

    void addApplicationListenerBean(String var1);

    void removeApplicationListener(ApplicationListener<?> var1);

    void removeApplicationListenerBean(String var1);

    void removeAllListeners();

    void multicastEvent(ApplicationEvent var1);

    void multicastEvent(ApplicationEvent var1, @Nullable ResolvableType var2);
}

AbstractApplicationEventMulticaster — это абстрактная реализация интерфейса ApplicationEventMulticaster, предоставляющая самые основные методы регистрации прослушивателя. При регистрации прослушивателя обычно не разрешается регистрировать несколько экземпляров одного и того же прослушивателя, поэтому для дедупликации используется коллекция Set. Тогда конкретная реализация широковещательного события здесь не реализуется, а передается для реализации подклассу SimpleApplicationEventMulticaster.

Ключевой код абстрактного класса AbstractApplicationEventMulticaster выглядит следующим образом:

	// AbstractApplicationEventMulticaster.java

        /**
	 * 获取事件监听器的帮助类,拥有Set<ApplicationListener<?>>属性
	 */
	private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);
	/**
	 * ListenerRetriever缓存
	 * key:ListenerCacheKey  value:ListenerRetriever
	 */
	final Map<ListenerCacheKey, ListenerRetriever> retrieverCache = new ConcurrentHashMap<>(64);

        // 添加spring监听器到ListenerRetriever的applicationListeners集合中
	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();
		}
	}

        // 移除监听器
	public void removeApplicationListener(ApplicationListener<?> listener) {
		synchronized (this.retrievalMutex) {
			this.defaultRetriever.applicationListeners.remove(listener);
			this.retrieverCache.clear();
		}
	}

        // 移除所有监听器
	public void removeAllListeners() {
		synchronized (this.retrievalMutex) {
			this.defaultRetriever.applicationListeners.clear();
			this.defaultRetriever.applicationListenerBeans.clear();
			this.retrieverCache.clear();
		}
	}

        // 利用defaultRetriever得到所有的监听器
	protected Collection<ApplicationListener<?>> getApplicationListeners() {
		synchronized (this.retrievalMutex) {
			return this.defaultRetriever.getApplicationListeners();
		}
	}

    
    

В приведенном выше коде вы заметили, что добавление, удаление и последующие прослушиватели AbstractApplicationEventMulticaster делегируются его внутреннему классу ListenerRetriever, поскольку ListenerRetriever внутренне поддерживает набор прослушивателей Set>. Давайте посмотрим на ключевой код внутреннего класса ListenerRetriever:

private class ListenerRetriever {
		/**
		 * 监听器集合
		 */
		public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();

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

		private final boolean preFiltered;

		public ListenerRetriever(boolean preFiltered) {
			this.preFiltered = preFiltered;
		}

		/**
		 * 获取所有的spring监听器
		 * @return
		 */
		public Collection<ApplicationListener<?>> getApplicationListeners() {
			List<ApplicationListener<?>> 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;
		}
	}

Давайте взглянем на ключевой код класса SimpleApplicationEventMulticaster, который выполняет широковещательное событие:

public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
        // 执行广播异步事件的线程
	@Nullable
	private Executor taskExecutor;
        // 广播异步事件的线程时出现异常时的处理器
	@Nullable
	private ErrorHandler errorHandler;


	/**
	 * Create a new SimpleApplicationEventMulticaster.
	 */
	public SimpleApplicationEventMulticaster() {
	}


	@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));
		// 获取执行异步任务的线程池,这里异步要外部指定一个线程池,注入进来
		Executor executor = getTaskExecutor();
		// 遍历每一个spring事件监听器
		for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
			// 若外部指定的线程池不为null,则异步广播事件
			if (executor != null) {
				executor.execute(() -> invokeListener(listener, event));
			}
			// executor为空,则单线程同步广播事件
			else {
				invokeListener(listener, event);
			}
		}
	}

	protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
		ErrorHandler errorHandler = getErrorHandler();
		// errorHandler不为空的情况下,则会进入try...catch..代码块,这里会对异步广播事件发生的异常进行处理
		if (errorHandler != null) {
			try {
				// 这里真正执行广播事件的逻辑
				doInvokeListener(listener, event);
			}
			catch (Throwable err) {
				// 处理异常
				errorHandler.handleError(err);
			}
		}
		// errorHandler为空的情况下,则不对出现的异常进行处理
		else {
			doInvokeListener(listener, event);
		}
	}

	@SuppressWarnings({"rawtypes", "unchecked"})
	private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
		try {
			// 回调监听器onApplicationEvent方法,执行监听逻辑
			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.isTraceEnabled()) {
					logger.trace("Non-matching event type for listener: " + listener, ex);
				}
			}
			else {
				throw ex;
			}
		}
	}

}

SimpleApplicationEventMulticaster — это класс реализации ApplicationEventMulticaster. Он отвечает за широковещательную передачу всех событий зарегистрированным слушателям spring, позволяя слушателям решать, какие события им интересны. Слушатели будут выполнять instanof, чтобы определить, являются ли они интересными событиями. По умолчанию все слушатели будут блокироваться и выполняться синхронно в вызывающем потоке, то есть в одном потоке, поэтому, если количество слушателей слишком велико или время выполнения слушателя слишком велико, это приведет к тому, что контейнер Spring перестанет работать. слишком долго начинать. Тем не менее, SimpleApplicationEventMulticaster также предоставляет функцию асинхронного широковещательного времени, получает пул потоков через taskExecutor, а затем транслирует события в несколько потоков.Кроме того, он также поддерживает атрибут объекта errorHandler, обработчик исключений, errorHandler в основном используется при асинхронных если прослушивание Когда обработчик выполняется ненормально, он используется для обработки перехваченного исключения в это время.

2.4 ApplicationEventPublisher

Точно так же сначала взгляните на следующую диаграмму классов

Видно, что родительский интерфейс ApplicationContext всех контейнеров Spring наследует интерфейс ApplicationEventPublisher, поэтому контейнер Spring обычно имеет функцию трансляции событий.

Давайте посмотрим на код класса интерфейса ApplicationEventPublisher:

@FunctionalInterface
public interface ApplicationEventPublisher {
    default void publishEvent(ApplicationEvent event) {
        this.publishEvent((Object)event);
    }

    void publishEvent(Object event);
}

Этот интерфейс инкапсулирует общедоступный метод публикации событий.В качестве суперинтерфейса ApplicationContext коллеги также доверяют ApplicationEventMulticaster для завершения публикации событий.

Давайте посмотрим, как контейнер Spring публикует события после реализации интерфейса ApplicationEventPublisher.На данный момент мы должны сначала взглянуть на родительский интерфейс ApplicationContext контейнера Spring, поскольку этот интерфейс наследует интерфейс ApplicationEventPublisher, поэтому контейнер Spring имеет возможность публиковать события.

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
		MessageSource, ApplicationEventPublisher, ResourcePatternResolver {

        // 省略接口方法
        
        }

Итак, как контейнер Spring публикует события? Интерфейс ApplicationEventMulticaster уже упоминался ранее, да, контекст контейнера spring доверен для реализации функции публикации событий. Поскольку AbstractApplicationContext реализует интерфейс ConfigurableApplicationContext, через который окончательно реализуется интерфейс ApplicationEventPublisher, метод публикации событий в контейнере spring инкапсулирован в методе publishEvent класса AbstractApplicationContext.

Взгляните на соответствующий код ниже:

public abstract class AbstractApplicationContext extends DefaultResourceLoader
		implements ConfigurableApplicationContext {
	/**
	 * 父类context
	 */
	@Nullable
	private ApplicationContext parent;

	/**
	 * 在multicaster setup前,发布事件
	 */
	@Nullable
	private Set<ApplicationEvent> earlyApplicationEvents;

	// 发布事件给所有事件监听器,
	protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
		Assert.notNull(event, "Event must not be null");

		// 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...
		if (this.parent != null) {
			if (this.parent instanceof AbstractApplicationContext) {
				((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
			}
			else {
				this.parent.publishEvent(event);
			}
		}
	}
}

Наконец, разобравшись с механизмом исходного кода, вы сможете сделать это самостоятельно.Рекомендуется прочитать следующие практические статьи:

Весенние пользовательские публикации и мониторинг и мониторинг событий (простой пример)

Резюме: Эта статья - моя вторая статья по анализу исходного кода, и скорость написания по-прежнему очень низкая. Надеюсь, что смогу закончить ее вскоре после того, как очищу свой разум.

Ссылаться на:

spring.io/docs