框架:SpringBoot 之 SpringApplication源碼深度解析(上)

總算是懷着熱切的心情打開了spring boot的源碼,大四北京實習用過的框架,都是回憶呀。

啓動類,都是調用SpringApplication的run()方法,傳入的是加入@Configuration註解的類,跟參數:

	public static ConfigurableApplicationContext run(Class<?> primarySource,
			String... args) {
		return run(new Class<?>[] { primarySource }, args);
	}
	public static ConfigurableApplicationContext run(Class<?>[] primarySources,
			String[] args) {
		return new SpringApplication(primarySources).run(args);
	}

先初始化了SpringApplication的實例然後調用run方法。先看其構造吧:

	public SpringApplication(Class<?>... primarySources) {
		this(null, primarySources);
	}
	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		this.webApplicationType = deduceWebApplicationType();
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}

在其雙參構造方法中可以看到,先是保存傳入的resourceLoader,對資源非null斷言,將資源primarySources按照有序LinkedSet形式存儲,調用deduceWebApplication()方法推斷出webApplication的類型,然後設置initializers、listeners、用deduceMainApplicationClass()方法得出並設置mainApplicationClass。

先看deduceWebApplication()方法:
 

	private WebApplicationType deduceWebApplicationType() {
		if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
				&& !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)
				&& !ClassUtils.isPresent(JERSEY_WEB_ENVIRONMENT_CLASS, null)) {
			return WebApplicationType.REACTIVE;
		}
		for (String className : WEB_ENVIRONMENT_CLASSES) {
			if (!ClassUtils.isPresent(className, null)) {
				return WebApplicationType.NONE;
			}
		}
		return WebApplicationType.SERVLET;
	}

可以看到這裏通過ClassUtils類的isPresent()方法檢查classpath中是否有相應的類來判斷類型:

        private static final String[] WEB_ENVIRONMENT_CLASSES = 
                        { "javax.servlet.Servlet","org.springframework.web.context.ConfigurableWebApplicationContext" };	
        public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
			+ "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";
 
	private static final String REACTIVE_WEB_ENVIRONMENT_CLASS = "org.springframework."
			+ "web.reactive.DispatcherHandler";
 
	private static final String MVC_WEB_ENVIRONMENT_CLASS = "org.springframework."
			+ "web.servlet.DispatcherServlet";
 
	private static final String JERSEY_WEB_ENVIRONMENT_CLASS = "org.glassfish.jersey.server.ResourceConfig";

如果有dispatcherHandler,且沒有DispatcherServlet、jersy的就是Reactive類型,如果沒有WEB_ENVIRONMENT_CLASSES 
指定的類,那麼則None類型,否則Servlet類型。

在設置Initializers時首先調用getSpringFactoriesInstances()方法加載ApplicationContextInitializer,然後直接賦值給initializers:

	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
		return getSpringFactoriesInstances(type, new Class<?>[] {});
	}
	private <T> Collection<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<>(
				SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
				classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

可以看到這裏通過spring容器來實現IoC。先得到contextClassLoader,然後調用SpringFactoriesLoader的loadFactoryNames傳入factoryClass得到該Class下配置的類名的集合,這裏使用set來存,保證類名不重複。然後調用createSpringFactoriesInstances()方法,得到對應的實例的集合,再排序返回。

我們先來看下loadFactoryNames()方法的邏輯:

    public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
    }

先得到factoryClass的名字,這裏即org.springframework.context.ApplicationContextInitializer,然後調用loadSpringFactories()傳入ClassLoader,得到map,然後用factoryClass的名字作爲key去get:

    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
        if(result != null) {
            return result;
        } else {
            try {
                Enumeration<URL> urls = classLoader != null?classLoader.getResources("META-INF/spring.factories")
                                                        :ClassLoader.getSystemResources("META-INF/spring.factories");
                LinkedMultiValueMap result = new LinkedMultiValueMap();
 
                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();
 
                    while(var6.hasNext()) {
                        Entry<?, ?> entry = (Entry)var6.next();
                        List<String> factoryClassNames = Arrays.asList(StringUtils.commaDelimitedListToStringArray
                                                                                            ((String)entry.getValue()));
                        result.addAll((String)entry.getKey(), factoryClassNames);
                    }
                }
 
                cache.put(classLoader, result);
                return result;
            } catch (IOException var9) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var9);
            }
        }
    }

這兒有個MultiValueMap類型的緩存,如果緩存裏面有classLoader加載過的,那麼直接返回,否則重新加載。先得到ClassLoader加載的urls,如果ClassLoader爲null那麼從ClassLoader默認的系統配置中去取,否則從ClassLoader中去取"META-INF/spring.factories"路徑下的urls。然後遍歷urls,取出每個url對應的properties文件,取出其中的鍵值對加入到LinkedMultiValueMap中,最後以ClassLoader爲key,LinkedMultiValueMap爲value加入到cache中緩存。返回的是LinkedMultiValueMap(該ClassLoader下的所有的urls指向的資源裏的properties中的鍵值對,其中值可能含有多個結果於是用list存儲)。

然後從返回的LinkedMultiValueMap中按照factoryClassName爲key,去取的對應的value集合。其中spring-boot/META-INF/spring.factories中org.springframework.context.ApplicationContextInitializer的值如下:

# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer

再來關注下SpringApplication的createSpringFactoriesInstances()方法:

	private <T> List<T> createSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
			Set<String> names) {
		List<T> instances = new ArrayList<>(names.size());
		for (String name : names) {
			try {
				Class<?> instanceClass = ClassUtils.forName(name, classLoader);
				Assert.isAssignable(type, instanceClass);
				Constructor<?> constructor = instanceClass
						.getDeclaredConstructor(parameterTypes);
				T instance = (T) BeanUtils.instantiateClass(constructor, args);
				instances.add(instance);
			}
			catch (Throwable ex) {
				throw new IllegalArgumentException(
						"Cannot instantiate " + type + " : " + name, ex);
			}
		}
		return instances;
	}

這個邏輯很簡單,先遍歷類名的集合,通過ClassUtils的forName反射出每個類名對應的類,再得到其對應的構造方法,再調用BeanUtils的instantiateClass()反射得到具體實例對象,加入到instances集合中。返回。然後加到initializers中。

設置listener還是一樣的方法,調用getSpringFactoriesInstances加載META-INF/spring.factories中配置的org.springframework.context.ApplicationListener指定的類,然後得到實例加到listeners中:

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

然後調用deduceMainApplicationClass()方法得到mainApplicationClass:

	private Class<?> deduceMainApplicationClass() {
		try {
			StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
			for (StackTraceElement stackTraceElement : stackTrace) {
				if ("main".equals(stackTraceElement.getMethodName())) {
					return Class.forName(stackTraceElement.getClassName());
				}
			}
		}
		catch (ClassNotFoundException ex) {
			// Swallow and continue
		}
		return null;
	}

 

通過獲取當前方法調用棧,遍歷找到main函數的類。

下面構造完成了,我們來看看SpringApplication實例的run方法:

	public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(
					SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass)
						.logStarted(getApplicationLog(), stopWatch);
			}
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}
 
		try {
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

先創建StopWatch做爲計時工具,然後調用其start方法,記錄當前時間即開始計時:

    public void start() throws IllegalStateException {
        this.start("");
    }
 
    public void start(String taskName) throws IllegalStateException {
        if(this.currentTaskName != null) {
            throw new IllegalStateException("Can't start StopWatch: it's already running");
        } else {
            this.currentTaskName = taskName;
            this.startTimeMillis = System.currentTimeMillis();
        }
    }

我們可以看看StopWatch的stop停止計時:

    public void stop() throws IllegalStateException {
        if(this.currentTaskName == null) {
            throw new IllegalStateException("Can't stop StopWatch: it's not running");
        } else {
            long lastTime = System.currentTimeMillis() - this.startTimeMillis;
            this.totalTimeMillis += lastTime;
            this.lastTaskInfo = new StopWatch.TaskInfo(this.currentTaskName, lastTime);
            if(this.keepTaskList) {
                this.taskList.add(this.lastTaskInfo);
            }
 
            ++this.taskCount;
            this.currentTaskName = null;
        }
    }

初始化TaskInfo傳入開始時間,結束時間。將Task加入TaskList中,taskCount++,再currentTaskName設爲null,表示現在沒計時任務。
然後調用configureHeadlessProperty設置SYSTEM_PROPERTY_JAVA_AWT_HEADLESS系統屬性,這裏headless默認值爲true,表示是Headless模式,在缺少顯示屏、鍵盤或者鼠標時的系統配置:

	private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless";
        private void configureHeadlessProperty() {
		System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(
				SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
	}

然後調用getRunListenners():

	private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
				SpringApplicationRunListener.class, types, this, args));
	}

在這裏可以看到又用了同樣的方法得到getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, arg)得到SpringApplicationRunListener類名爲key,在META-INF/spring.factories裏的值:

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

只加載了EventPublishingRunListener類,我們看其構造方法:

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

這裏構造了一個SimpleApplicationEventMulticaster(Spring默認的事件廣播器)實例,並且把之前在SpringApplication中配置的listeners添加到SimpleApplicationEventMulticaster中。

然後跟log一起封裝成SpringApplicationRunListeners:

	SpringApplicationRunListeners(Log log,
			Collection<? extends SpringApplicationRunListener> listeners) {
		this.log = log;
		this.listeners = new ArrayList<>(listeners);
	}

緊接下來就直接調用其starting方法:

	public void starting() {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.starting();
		}
	}

我們知道,這個listeners其實只有一個,EventPublishingRunListener的實例。我們看到EventPublishingRunListener的starting方法中:

	@Override
	public void starting() {
		this.initialMulticaster.multicastEvent(
				new ApplicationStartingEvent(this.application, this.args));
	}

調用的是內部的SimpleApplicationEventMulticaster的multicastEvent方法,傳入新構造的ApplicationStartingEvent實例:

    public void multicastEvent(ApplicationEvent event) {
        this.multicastEvent(event, this.resolveDefaultEventType(event));
    }
 
    public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = eventType != null?eventType:this.resolveDefaultEventType(event);
        Iterator var4 = this.getApplicationListeners(event, type).iterator();
 
        while(var4.hasNext()) {
            ApplicationListener<?> listener = (ApplicationListener)var4.next();
            Executor executor = this.getTaskExecutor();
            if(executor != null) {
                executor.execute(() -> {
                    this.invokeListener(listener, event);
                });
            } else {
                this.invokeListener(listener, event);
            }
        }
 
    }

先通過getApplicationListenners得到處理該事件的Listenner集合:

    protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {
        Object source = event.getSource();
        Class<?> sourceType = source != null?source.getClass():null;
        AbstractApplicationEventMulticaster.ListenerCacheKey cacheKey = new AbstractApplicationEventMulticaster.ListenerCacheKey(eventType, sourceType);
        AbstractApplicationEventMulticaster.ListenerRetriever retriever = (AbstractApplicationEventMulticaster.ListenerRetriever)this.retrieverCache.get(cacheKey);
        if(retriever != null) {
            return retriever.getApplicationListeners();
        } else if(this.beanClassLoader == null || ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader))) {
            Object var7 = this.retrievalMutex;
            synchronized(this.retrievalMutex) {
                retriever = (AbstractApplicationEventMulticaster.ListenerRetriever)this.retrieverCache.get(cacheKey);
                if(retriever != null) {
                    return retriever.getApplicationListeners();
                } else {
                    retriever = new AbstractApplicationEventMulticaster.ListenerRetriever(true);
                    Collection<ApplicationListener<?>> listeners = this.retrieveApplicationListeners(eventType, sourceType, retriever);
                    this.retrieverCache.put(cacheKey, retriever);
                    return listeners;
                }
            }
        } else {
            return this.retrieveApplicationListeners(eventType, sourceType, (AbstractApplicationEventMulticaster.ListenerRetriever)null);
        }
    }

先通過傳入的event構造cacheKey,先去緩存中查找結果,如果結果不爲null,那麼直接返回,否則調用retrieveApplicationListeners,如果需要緩存即滿足以下條件(this.beanClassLoader==null|| ClassUtils.isCacheSafe(event.getClass(),this.beanClassLoader)&&(sourceType==null|| ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)),那麼需要加鎖,且將新生成的retriever以cacheKey爲鍵存入cache中。我們從下面retrieveApplicationListeners的實現中可以看到,遍歷Listenners跟listenerBeans通過supportsEvent判斷Listenner是否支持該事件,支持則加入到處理的集合中:

    private Collection<ApplicationListener<?>> retrieveApplicationListeners(ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable AbstractApplicationEventMulticaster.ListenerRetriever retriever) {
        LinkedList<ApplicationListener<?>> allListeners = new LinkedList();
        Object var7 = this.retrievalMutex;
        LinkedHashSet listeners;
        LinkedHashSet listenerBeans;
        synchronized(this.retrievalMutex) {
            listeners = new LinkedHashSet(this.defaultRetriever.applicationListeners);
            listenerBeans = new LinkedHashSet(this.defaultRetriever.applicationListenerBeans);
        }
 
        Iterator var14 = listeners.iterator();
 
        while(var14.hasNext()) {
            ApplicationListener<?> listener = (ApplicationListener)var14.next();
            if(this.supportsEvent(listener, eventType, sourceType)) {
                if(retriever != null) {
                    retriever.applicationListeners.add(listener);
                }
 
                allListeners.add(listener);
            }
        }
 
        if(!listenerBeans.isEmpty()) {
            BeanFactory beanFactory = this.getBeanFactory();
            Iterator var16 = listenerBeans.iterator();
 
            while(var16.hasNext()) {
                String listenerBeanName = (String)var16.next();
 
                try {
                    Class<?> listenerType = beanFactory.getType(listenerBeanName);
                    if(listenerType == null || this.supportsEvent(listenerType, eventType)) {
                        ApplicationListener<?> listener = (ApplicationListener)beanFactory.getBean(listenerBeanName, ApplicationListener.class);
                        if(!allListeners.contains(listener) && this.supportsEvent(listener, eventType, sourceType)) {
                            if(retriever != null) {
                                retriever.applicationListenerBeans.add(listenerBeanName);
                            }
 
                            allListeners.add(listener);
                        }
                    }
                } catch (NoSuchBeanDefinitionException var13) {
                    ;
                }
            }
        }
 
        AnnotationAwareOrderComparator.sort(allListeners);
        return allListeners;
    }

當前listeners中:

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

listenerBeans集合爲空,其中支持ApplicationStartedEvent事件的Listenner剩下:

org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

回到SimpleApplicationEventMulticaster的multicastEvent方法,在得到相關事件的listenners集合後,然後遍歷listeners,如果listener有線程池則通過線程池執行invokeListener,沒有的話則直接執行:

    protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
        ErrorHandler errorHandler = this.getErrorHandler();
        if(errorHandler != null) {
            try {
                this.doInvokeListener(listener, event);
            } catch (Throwable var5) {
                errorHandler.handleError(var5);
            }
        } else {
            this.doInvokeListener(listener, event);
        }
 
    }

繼續調用doInvokeListener,如果有error的函數句柄,則try-catch,出錯執行:

    private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
        try {
            listener.onApplicationEvent(event);
        } catch (ClassCastException var6) {
            String msg = var6.getMessage();
            if(msg != null && !this.matchesClassCastMessage(msg, event.getClass().getName())) {
                throw var6;
            }
 
            Log logger = LogFactory.getLog(this.getClass());
            if(logger.isDebugEnabled()) {
                logger.debug("Non-matching event type for listener: " + listener, var6);
            }
        }
 
    }

執行listener的相應事件。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章