本文共 9696 字,大约阅读时间需要 32 分钟。
版本:2.0.8.RELEASE
A SpringApplication
attempts to create the right type of ApplicationContext
on your behalf. The algorithm used to determine a WebApplicationType
is fairly simple:
AnnotationConfigServletWebServerApplicationContext
is usedAnnotationConfigReactiveWebServerApplicationContext
is usedAnnotationConfigApplicationContext
is usedThis means that if you are using Spring MVC and the new WebClient
from Spring WebFlux in the same application, Spring MVC will be used by default. You can override that easily by calling setWebApplicationType(WebApplicationType)
.
It is also possible to take complete control of the ApplicationContext
type that is used by calling setApplicationContextClass(…)
.
It is often desirable to call |
下面从项目启动源码中看这段话的理解:
启动类中的main方法:首先创建一个SpringApplication的实例,执行实例的run方法。
public static void main( String[] args ) { SpringApplication app = new SpringApplication(Application.class); app.run(); }
/** * Create a new {@link SpringApplication} instance. The application context will load * beans from the specified primary sources (see {@link SpringApplication class-level} * documentation for details. The instance can be customized before calling * {@link #run(String...)}. * @param primarySources the primary bean sources * @see #run(Class, String[]) * @see #SpringApplication(ResourceLoader, Class...) * @see #setSources(Set) */ public SpringApplication(Class ... primarySources) { this(null, primarySources); }
/** * Create a new {@link SpringApplication} instance. The application context will load * beans from the specified primary sources (see {@link SpringApplication class-level} * documentation for details. The instance can be customized before calling * {@link #run(String...)}. * @param resourceLoader the resource loader to use * @param primarySources the primary bean sources * @see #run(Class, String[]) * @see #setSources(Set) */ @SuppressWarnings({ "unchecked", "rawtypes" }) public SpringApplication(ResourceLoader resourceLoader, Class ... primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); //从类路径中判断web应用类型 this.webApplicationType = WebApplicationType.deduceFromClasspath(); //使用SpringFactoriesLoader在应用的classpath查找并加载所有可用的 ApplicationContextInitializer。返回的是应用的classpath中所有jar包中META-INF/spring.factories文件中定义的 org.springframework.context.ApplicationContextInitializer的值的集合并创建这些类的实例 setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); //使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationListener。同上 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }
下面看webApplicationType是如何判断的:WebApplicationType 枚举类的方法deduceFromClasspath
- 如果类路径中有类org.springframework.web.reactive.DispatcherHandler,且没有org.springframework.web.servlet.DispatcherServlet和org.glassfish.jersey.servlet.ServletContainer,WebApplicationType为REACTIVE
- 否则看类路径中"javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext"这两个类有一个不存在就返回NONE
- 否则就为SERVLET
/* * Copyright 2012-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.springframework.boot;import org.springframework.util.ClassUtils;/** * An enumeration of possible types of web application. * * @author Andy Wilkinson * @author Brian Clozel * @since 2.0.0 */public enum WebApplicationType { /** * The application should not run as a web application and should not start an * embedded web server. */ NONE, /** * The application should run as a servlet-based web application and should start an * embedded servlet web server. */ SERVLET, /** * The application should run as a reactive web application and should start an * embedded reactive web server. */ REACTIVE; private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext" }; private static final String WEBMVC_INDICATOR_CLASS = "org.springframework." + "web.servlet.DispatcherServlet"; private static final String WEBFLUX_INDICATOR_CLASS = "org." + "springframework.web.reactive.DispatcherHandler"; private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer"; private static final String SERVLET_APPLICATION_CONTEXT_CLASS = "org.springframework.web.context.WebApplicationContext"; private static final String REACTIVE_APPLICATION_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext"; static WebApplicationType deduceFromClasspath() { if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) { return WebApplicationType.REACTIVE; } for (String className : SERVLET_INDICATOR_CLASSES) { if (!ClassUtils.isPresent(className, null)) { return WebApplicationType.NONE; } } return WebApplicationType.SERVLET; } static WebApplicationType deduceFromApplicationContext( Class applicationContextClass) { if (isAssignable(SERVLET_APPLICATION_CONTEXT_CLASS, applicationContextClass)) { return WebApplicationType.SERVLET; } if (isAssignable(REACTIVE_APPLICATION_CONTEXT_CLASS, applicationContextClass)) { return WebApplicationType.REACTIVE; } return WebApplicationType.NONE; } private static boolean isAssignable(String target, Class type) { try { return ClassUtils.resolveClassName(target, null).isAssignableFrom(type); } catch (Throwable ex) { return false; } }}
/** * Run the Spring application, creating and refreshing a new * {@link ApplicationContext}. * @param args the application arguments (usually passed from a Java main method) * @return a running {@link ApplicationContext} */ public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; CollectionexceptionReporters = 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; }
从run方法的createApplicationContext方法中可以看出使用的哪种ApplicationContext类型
如果
webApplicationType是SERVLET类型,ApplicationContext就是
AnnotationConfigServletWebServerApplicationContext
如果
webApplicationType是REACTIVE类型,ApplicationContext就是
AnnotationConfigReactiveWebServerApplicationContext
否则ApplicationContext就是
AnnotationConfigApplicationContext
/** * Strategy method used to create the {@link ApplicationContext}. By default this * method will respect any explicitly set application context or application context * class before falling back to a suitable default. * @return the application context (not yet refreshed) * @see #setApplicationContextClass(Class) */ protected ConfigurableApplicationContext createApplicationContext() { Class contextClass = this.applicationContextClass; if (contextClass == null) { try { switch (this.webApplicationType) { case SERVLET: contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS); break; case REACTIVE: contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS); break; default: contextClass = Class.forName(DEFAULT_CONTEXT_CLASS); } } catch (ClassNotFoundException ex) { throw new IllegalStateException( "Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass", ex); } } return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass); }
转载地址:http://erivi.baihongyu.com/