spring boot實戰(第三篇)事件監聽源碼分析
前言
解讀源碼,知其然知其所以然···
監聽源碼分析
首先來看下上一篇中執行的main方法
package com.lkl.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.lkl.springboot.listener.MyApplicationStartedEventListener;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application.class);
//app.setAdditionalProfiles("dev");
app.addListeners(new MyApplicationStartedEventListener());
app.run(args);
}
}
SpringApplication app = new SpringApplication(Application.class)
創建一個SpringApplication
實例;創建實例執行對象構造方法;其構造方法如下:
public SpringApplication(Object... sources) {
initialize(sources);
}
調用initialize()
,該方法執行若干初始化操作,在後續再繼續深入該方法。
app.addListeners(new MyApplicationStartedEventListener());
調用SpringApplication
添加監聽的方法執行操作:
public void addListeners(ApplicationListener<?>... listeners) {
this.listeners.addAll(Arrays.asList(listeners));
}
this.listeners
爲List<ApplicationListener<?>>
類型,是SpringApplication
中所有監聽器的持有容器(在initialize()
方法中也會往該監聽集合中添加初始化的監聽器)
執行完添加監聽器方法後執行app.run(args)
方法
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
System.setProperty(
SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
Boolean.toString(this.headless)));
Collection<SpringApplicationRunListener> runListeners = getRunListeners(args);
for (SpringApplicationRunListener runListener : runListeners) {
runListener.started();
}
try {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, args);
for (SpringApplicationRunListener runListener : runListeners) {
runListener.environmentPrepared(environment);
}
if (this.showBanner) {
printBanner(environment);
}
// Create, load, refresh and run the ApplicationContext
context = createApplicationContext();
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
for (SpringApplicationRunListener runListener : runListeners) {
runListener.contextPrepared(context);
}
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
}
// Load the sources
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[sources.size()]));
for (SpringApplicationRunListener runListener : runListeners) {
runListener.contextLoaded(context);
}
// Refresh the context
refresh(context);
afterRefresh(context, args);
for (SpringApplicationRunListener runListener : runListeners) {
runListener.finished(context, null);
}
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(
getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
try {
for (SpringApplicationRunListener runListener : runListeners) {
finishWithException(runListener, context, ex);
}
this.log.error("Application startup failed", ex);
}
finally {
if (context != null) {
context.close();
}
}
ReflectionUtils.rethrowRuntimeException(ex);
return context;
}
}
在run()
方法中完成了spring boot的啓動,方法代碼比較長,本篇重點放在事件監聽上;
Collection<SpringApplicationRunListener> runListeners = getRunListeners(args)
通過getRunListeners(args)
獲取執行時監聽的集合,其代碼如下:
private Collection<SpringApplicationRunListener> getRunListeners(String[] args) {
List<SpringApplicationRunListener> listeners = new ArrayList<SpringApplicationRunListener>();
listeners.addAll(getSpringFactoriesInstances(SpringApplicationRunListener.class,
new Class<?>[] { SpringApplication.class, String[].class }, this, args));
return listeners;
}
重點關注
getSpringFactoriesInstances(SpringApplicationRunListener.class,
該方法獲取執行類型子類實例集合
new Class<?>[] { SpringApplication.class, String[].class }, this, args)
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<String>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = new ArrayList<T>(names.size());
// Create instances from the names
for (String name : names) {
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
Constructor<?> constructor = instanceClass.getConstructor(parameterTypes);
T instance = (T) constructor.newInstance(args);
instances.add(instance);
}
catch (Throwable ex) {
throw new IllegalArgumentException("Cannot instantiate " + type + " : "
+ name, ex);
}
}
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
看 SpringFactoriesLoader.loadFactoryNames(type, classLoader)
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
try {
Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
List<String> result = new ArrayList<String>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
String factoryClassNames = properties.getProperty(factoryClassName);
result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
}
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
"] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
其中
Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) ;
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
通過類加載器獲取resources;FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
代碼回去掃描項目工程中/META-INF下的spring.factories文件,獲取org.springframework.boot.SpringApplicationRunListener
對應數據
在spring-boot-1.2.4.RELEASE
中可以找到如下信息
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
即通過Collection<SpringApplicationRunListener> runListeners = getRunListeners(args);
最終拿到的是EventPublishingRunListener
。
在獲取EventPublishingRunListener
實例時,執行對應構造方法
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.multicaster = new SimpleApplicationEventMulticaster();
for (ApplicationListener<?> listener : application.getListeners()) {
this.multicaster.addApplicationListener(listener);
}
}
將SpringApplication
中的監聽器傳遞給SimpleApplicationEventMulticaster
實例multicaster
執行
for (SpringApplicationRunListener runListener : runListeners) {
runListener.started();
}
調用EventPublishingRunListener
中的started()
方法
@Override
public void started() {
publishEvent(new ApplicationStartedEvent(this.application, this.args));
}
在該方法中首先創建一個ApplicationStartedEvent
事件,將this.application
傳遞過去,因此在執行ApplicationStartedEvent
監聽時可以獲取SpringApplication
實例。
執行publishEvent()
方法
private void publishEvent(SpringApplicationEvent event) {
this.multicaster.multicastEvent(event);
}
調用SimpleApplicationEventMulticaster#multicastEvent(event)
@Override
public void multicastEvent(final ApplicationEvent event) {
for (final ApplicationListener<?> listener : getApplicationListeners(event)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(new Runnable() {
@Override
public void run() {
invokeListener(listener, event);
}
});
}
else {
invokeListener(listener, event);
}
}
}
在該代碼中需要注意的是for循環中獲取監聽器集合方getApplicationListeners(event)
,由於傳遞的事件爲ApplicationStartedEvent
,因此該方法需要獲取到ApplicationStartedEvent
對應的監聽器
protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event) {
Object source = event.getSource();
Class<?> sourceType = (source != null ? source.getClass() : null);
ListenerCacheKey cacheKey = new ListenerCacheKey(event.getClass(), 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<ApplicationListener<?>> listeners =
retrieveApplicationListeners(event, sourceType, retriever);
this.retrieverCache.put(cacheKey, retriever);
return listeners;
}
}
else {
// No ListenerRetriever caching -> no synchronization necessary
return retrieveApplicationListeners(event, sourceType, null);
}
}
看retrieveApplicationListeners(event, sourceType, null)
方法;該方法代碼比較長,截取一部分出來
private Collection<ApplicationListener<?>> retrieveApplicationListeners(
ApplicationEvent event, Class<?> sourceType, ListenerRetriever retriever) {
LinkedList<ApplicationListener<?>> allListeners = new LinkedList<ApplicationListener<?>>();
Set<ApplicationListener<?>> listeners;
Set<String> listenerBeans;
synchronized (this.retrievalMutex) {
listeners = new LinkedHashSet<ApplicationListener<?>>(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet<String>(this.defaultRetriever.applicationListenerBeans);
}
for (ApplicationListener<?> listener : listeners) {
if (supportsEvent(listener, event.getClass(), sourceType)) {
if (retriever != null) {
retriever.applicationListeners.add(listener);
}
allListeners.add(listener);
}
}
...
OrderComparator.sort(allListeners);
return allListeners;
}
調用supportsEvent
方法判斷對應的監聽器是否支持指定的事件
protected boolean supportsEvent(ApplicationListener<?> listener,
Class<? extends ApplicationEvent> eventType, Class<?> sourceType) {
SmartApplicationListener smartListener = (listener instanceof SmartApplicationListener ?
(SmartApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}
執行 GenericApplicationListenerAdapter#supportsEventType(eventType)
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
Class<?> declaredEventType = resolveDeclaredEventType(this.delegate.getClass());
if (declaredEventType == null || declaredEventType.equals(ApplicationEvent.class)) {
Class<?> targetClass = AopUtils.getTargetClass(this.delegate);
if (targetClass != this.delegate.getClass()) {
declaredEventType = resolveDeclaredEventType(targetClass);
}
}
return (declaredEventType == null || declaredEventType.isAssignableFrom(eventType));
}
調用resolveDeclaredEventType()
方法獲取指定類繼承的父類或實現接口時傳遞的泛型對應的類型,這句話有點繞口,可以自行看一下
static Class<?> resolveDeclaredEventType(Class<?> listenerType) {
return GenericTypeResolver.resolveTypeArgument(listenerType, ApplicationListener.class);
}
GenericTypeResolver
泛型解析工具類功能強大,我們在實際開發中同樣可以利用。
至此getApplicationListeners(event)
調用完成,大體思路爲:遍歷所有的監聽器,如果該監聽器監聽的事件爲傳遞的事件或傳遞事件的父類則表示該監聽器支持指定事件。
獲取完指定事件對應監聽器後,通過Executor
執行一個子線程去完成監聽器listener.onApplicationEvent(event)
方法。
至此,事件監聽源碼解析結束,其他三個事件對應的源碼和此類同。
轉載請註明
http://blog.csdn.net/liaokailin/article/details/48194777