springboot原始碼解析之SpringApplication初始化、啟動
說在前面
本次開始spring-boot原始碼解析,更多精彩原始碼解析文章請關注”天河聊架構“微信公眾號。
原始碼解析
建立SpringApplication物件進入到這個方法org.springframework.boot.SpringApplication#SpringApplication(java.lang.Object...)
public SpringApplication(Object... sources) { initialize(sources); }
進入到這個方法org.springframework.boot.SpringApplication#initialize
private void initialize(Object[] sources) { if (sources != null && sources.length > 0) { this.sources.addAll(Arrays.asList(sources)); } this.webEnvironment = deduceWebEnvironment(); // 載入初始化器 setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); // 載入監聽器 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }
進入到這個方法org.springframework.boot.SpringApplication#getSpringFactoriesInstances(java.lang.Class<T>)從META-INF/spring.factories路徑載入ApplicationContextInitializer
# Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\ org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer
# 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.context.embedded.ServerPortInfoApplicationContextInitializer
進入到這個方法org.springframework.boot.SpringApplication#getSpringFactoriesInstances(java.lang.Class<T>)從META-INF/spring.factories路徑載入
ApplicationListener
# Application Listeners org.springframework.context.ApplicationListener=\ org.springframework.boot.autoconfigure.BackgroundPreinitializer
# 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.liquibase.LiquibaseServiceLocatorApplicationListener,\ org.springframework.boot.logging.ClasspathLoggingApplicationListener,\ org.springframework.boot.logging.LoggingApplicationListener
進入到這個方法org.springframework.boot.SpringApplication#deduceMainApplicationClass
根據main方法找到應用啟動類
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; }
進入到這個方法org.springframework.boot.SpringApplication#run(java.lang.String...)
// spring-boot原始碼解析 應用啟動 public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; FailureAnalyzers analyzers = null; configureHeadlessProperty(); // 初始化SpringApplicationRunListener -》 SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); // 列印banner Banner printedBanner = printBanner(environment); // 初始化spring上下文 -》 context = createApplicationContext(); analyzers = new FailureAnalyzers(context); // 準備spring上下文 -》 prepareContext(context, environment, listeners, applicationArguments, printedBanner); // 重新整理spring上下文 -》 refreshContext(context); // spring上下文初始化完畢載入其他applicationRunner afterRefresh(context, applicationArguments); // 執行監聽器spring載入完成事件 listeners.finished(context, null); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } return context; } catch (Throwable ex) { handleRunFailure(context, listeners, analyzers, ex); throw new IllegalStateException(ex); } }
進入到這個方法org.springframework.boot.SpringApplication#getRunListeners
private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances( SpringApplicationRunListener.class, types, this, args)); }
進入到這個方法org.springframework.boot.SpringApplication#getSpringFactoriesInstances(java.lang.Class<T>, java.lang.Class<?>[], java.lang.Object...)
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 // 載入META-INF/spring.factories配置的SpringApplicationRunListener監聽器 Set<String> names = new LinkedHashSet<String>( SpringFactoriesLoader.loadFactoryNames(type, classLoader)); // 建立META-INF/spring.factories配置的SpringApplicationRunListener監聽器物件 List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; }
進入到這個方法org.springframework.core.io.support.SpringFactoriesLoader#loadFactoryNames,從META-INF/spring.factories路徑下載入監聽器
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); try { Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories"); ArrayList result = new ArrayList(); while(urls.hasMoreElements()) { URL url = (URL)urls.nextElement(); Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url)); String propertyValue = properties.getProperty(factoryClassName); String[] var8 = StringUtils.commaDelimitedListToStringArray(propertyValue); int var9 = var8.length; for(int var10 = 0; var10 < var9; ++var10) { String factoryName = var8[var10]; result.add(factoryName.trim()); } } return result; } catch (IOException var12) { throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var12); } }
# Run Listeners org.springframework.boot.SpringApplicationRunListener=\ org.springframework.boot.context.event.EventPublishingRunListener
返回到這個方法建立監聽器的例項org.springframework.boot.SpringApplication#createSpringFactoriesInstances
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) { List<T> instances = new ArrayList<T>(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; }
進入到這個方法org.springframework.boot.context.event.EventPublishingRunListener#starting廣播應用啟動事件
@Override @SuppressWarnings("deprecation") public void starting() { this.initialMulticaster .multicastEvent(new ApplicationStartedEvent(this.application, this.args)); }
進入到這個方法org.springframework.boot.SpringApplication#createApplicationContext
protected ConfigurableApplicationContext createApplicationContext() { Class<?> contextClass = this.applicationContextClass; if (contextClass == null) { try { // 建立基於annotation的上下文物件 contextClass = Class.forName(this.webEnvironment ? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS); } catch (ClassNotFoundException ex) { throw new IllegalStateException( "Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass", ex); } } return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass); }
進入到這個方法org.springframework.boot.SpringApplication#prepareContext
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { context.setEnvironment(environment); postProcessApplicationContext(context); // 執行初始化器 =》 applyInitializers(context); // 執行監聽器上下文準備事件 -》 listeners.contextPrepared(context); if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // Add boot specific singleton beans context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { context.getBeanFactory().registerSingleton("springBootBanner", printedBanner); } // Load the sources Set<Object> sources = getSources(); Assert.notEmpty(sources, "Sources must not be empty"); // 載入bean定義 =》 load(context, sources.toArray(new Object[sources.size()])); // 執行spring上線文載入完成事件 -》 listeners.contextLoaded(context); }
進入這個方法org.springframework.boot.SpringApplication#postProcessApplicationContext,對applicationContext的後置處理
protected void postProcessApplicationContext(ConfigurableApplicationContext context) { if (this.beanNameGenerator != null) { context.getBeanFactory().registerSingleton( AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, this.beanNameGenerator); } if (this.resourceLoader != null) { if (context instanceof GenericApplicationContext) { ((GenericApplicationContext) context) .setResourceLoader(this.resourceLoader); } if (context instanceof DefaultResourceLoader) { ((DefaultResourceLoader) context) .setClassLoader(this.resourceLoader.getClassLoader()); } } }
返回到這個方法org.springframework.boot.SpringApplication#applyInitializers
@SuppressWarnings({ "rawtypes", "unchecked" }) protected void applyInitializers(ConfigurableApplicationContext context) { for (ApplicationContextInitializer initializer : getInitializers()) { Class<?> requiredType = GenericTypeResolver.resolveTypeArgument( initializer.getClass(), ApplicationContextInitializer.class); Assert.isInstanceOf(requiredType, context, "Unable to call initializer."); initializer.initialize(context); } }
進入這個方法org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer#initialize
@Override public void initialize(ConfigurableApplicationContext context) { context.addBeanFactoryPostProcessor( new ConfigurationWarningsPostProcessor(getChecks())); }
進入這個方法org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer#getChecks
protected Check[] getChecks() { return new Check[] { new ComponentScanPackageCheck() }; }
找到這裡
static { Set<String> packages = new HashSet<String>(); // 預設會掃描org.springframework下所有的包 packages.add("org.springframework"); packages.add("org"); PROBLEM_PACKAGES = Collections.unmodifiableSet(packages); }
springboot啟動的時候元件掃描器會預設掃描這兩個包。
進入這個方法org.springframework.boot.context.config.DelegatingApplicationContextInitializer#getInitializerClasses
private List<Class<?>> getInitializerClasses(ConfigurableEnvironment env) { // 載入初始化類context.initializer.classes String classNames = env.getProperty(PROPERTY_NAME); List<Class<?>> classes = new ArrayList<Class<?>>(); if (StringUtils.hasLength(classNames)) { for (String className : StringUtils.tokenizeToStringArray(classNames, ",")) { classes.add(getInitializerClass(className)); } } return classes; }
返回到這個方法org.springframework.boot.context.config.DelegatingApplicationContextInitializer#applyInitializerClasses
private void applyInitializerClasses(ConfigurableApplicationContext context, List<Class<?>> initializerClasses) { Class<?> contextClass = context.getClass(); List<ApplicationContextInitializer<?>> initializers = new ArrayList<ApplicationContextInitializer<?>>(); for (Class<?> initializerClass : initializerClasses) { // 初始化初始化器 initializers.add(instantiateInitializer(contextClass, initializerClass)); } applyInitializers(context, initializers); }
進入這個方法org.springframework.boot.context.config.DelegatingApplicationContextInitializer#applyInitializers
private void applyInitializers(ConfigurableApplicationContext context, List<ApplicationContextInitializer<?>> initializers) { Collections.sort(initializers, new AnnotationAwareOrderComparator()); for (ApplicationContextInitializer initializer : initializers) { // 執行初始化器的初始化方法 initializer.initialize(context); } }
返回到這個方法org.springframework.boot.SpringApplicationRunListeners#contextPrepared執行監聽器
public void contextPrepared(ConfigurableApplicationContext context) { for (SpringApplicationRunListener listener : this.listeners) { listener.contextPrepared(context); } }
進入到這個方法org.springframework.boot.SpringApplication#load載入bean定義
protected void load(ApplicationContext context, Object[] sources) { if (logger.isDebugEnabled()) { logger.debug( "Loading source " + StringUtils.arrayToCommaDelimitedString(sources)); } // 建立bean定義載入器 BeanDefinitionLoader loader = createBeanDefinitionLoader( getBeanDefinitionRegistry(context), sources); if (this.beanNameGenerator != null) { // 設定beanName生成器 loader.setBeanNameGenerator(this.beanNameGenerator); } if (this.resourceLoader != null) { loader.setResourceLoader(this.resourceLoader); } if (this.environment != null) { loader.setEnvironment(this.environment); } // 載入bean定義 =》 loader.load(); }
進入到這個方法org.springframework.boot.BeanDefinitionLoader#load(java.lang.Object)
private int load(Object source) { Assert.notNull(source, "Source must not be null"); if (source instanceof Class<?>) { return load((Class<?>) source); } if (source instanceof Resource) { return load((Resource) source); } // 註解掃描器載入bean定義 if (source instanceof Package) { return load((Package) source); } if (source instanceof CharSequence) { return load((CharSequence) source); } throw new IllegalArgumentException("Invalid source type " + source.getClass()); }
返回到這個方法org.springframework.boot.SpringApplicationRunListeners#contextLoaded處理監聽器
public void contextLoaded(ConfigurableApplicationContext context) { for (SpringApplicationRunListener listener : this.listeners) { listener.contextLoaded(context); } }
下面是初始化spring上下文請檢視spring原始碼解析系列文章有詳細的介紹。
初始化spring上下文後進入org.springframework.boot.SpringApplication#afterRefresh這個方法
protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) { callRunners(context, args); }
執行runners進入這個方法org.springframework.boot.SpringApplication#callRunners
private void callRunners(ApplicationContext context, ApplicationArguments args) { List<Object> runners = new ArrayList<Object>(); runners.addAll(context.getBeansOfType(ApplicationRunner.class).values()); runners.addAll(context.getBeansOfType(CommandLineRunner.class).values()); AnnotationAwareOrderComparator.sort(runners); for (Object runner : new LinkedHashSet<Object>(runners)) { if (runner instanceof ApplicationRunner) { callRunner((ApplicationRunner) runner, args); } if (runner instanceof CommandLineRunner) { callRunner((CommandLineRunner) runner, args); } } }
public interface ApplicationRunner { /** * Callback used to run the bean. * @param args incoming application arguments * @throws Exception on error */ void run(ApplicationArguments args) throws Exception; }
可以實現這個介面在spring上下文初始化完畢後去做一些處理。
進入這個方法org.springframework.boot.SpringApplicationRunListeners#finished
public void finished(ConfigurableApplicationContext context, Throwable exception) { for (SpringApplicationRunListener listener : this.listeners) { callFinishedListener(listener, context, exception); } }
進入這個方法org.springframework.boot.SpringApplicationRunListeners#callFinishedListener
private void callFinishedListener(SpringApplicationRunListener listener, ConfigurableApplicationContext context, Throwable exception) { try { listener.finished(context, exception); } catch (Throwable ex) { if (exception == null) { ReflectionUtils.rethrowRuntimeException(ex); } if (this.log.isDebugEnabled()) { this.log.error("Error handling failed", ex); } else { String message = ex.getMessage(); message = (message != null) ? message : "no error message"; this.log.warn("Error handling failed (" + message + ")"); } } }
執行監聽器的spring上下文載入完畢事件。
說在最後
本次僅代表個人觀