博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring Boot系列--Web环境
阅读量:4133 次
发布时间:2019-05-25

本文共 9696 字,大约阅读时间需要 32 分钟。

版本:2.0.8.RELEASE

23.6 Web Environment

SpringApplication attempts to create the right type of ApplicationContext on your behalf. The algorithm used to determine a WebApplicationType is fairly simple:

  • If Spring MVC is present, an AnnotationConfigServletWebServerApplicationContext is used
  • If Spring MVC is not present and Spring WebFlux is present, an AnnotationConfigReactiveWebServerApplicationContext is used
  • Otherwise, AnnotationConfigApplicationContext is used

This 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(…​).

[Tip]

It is often desirable to call setWebApplicationType(WebApplicationType.NONE) when using SpringApplication within a JUnit test.

 下面从项目启动源码中看这段话的理解:

启动类中的main方法:首先创建一个SpringApplication的实例,执行实例的run方法。

public static void main( String[] args ) {        SpringApplication app = new SpringApplication(Application.class);        app.run();    }

一、SpringApplication的实例创建源码

/**	 * 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方法源码

/**	 * 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;		Collection
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; }

从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/

你可能感兴趣的文章
经典shell面试题整理
查看>>
腾讯的一道面试题—不用除法求数字乘积
查看>>
素数算法
查看>>
java多线程环境单例模式实现详解
查看>>
将一个数插入到有序的数列中,插入后的数列仍然有序
查看>>
在有序的数列中查找某数,若该数在此数列中,则输出它所在的位置,否则输出no found
查看>>
万年历
查看>>
作为码农你希望面试官当场指出你错误么?有面试官这样遭到投诉!
查看>>
好多程序员都认为写ppt是很虚的技能,可事实真的是这样么?
查看>>
如果按照代码行数发薪水会怎样?码农:我能刷到公司破产!
查看>>
程序员失误造成服务停用3小时,只得到半月辞退补偿,发帖喊冤
查看>>
码农:很多人称我“技术”,感觉这是不尊重!纠正无果后果断辞职
查看>>
php程序员看过来,这老外是在吐糟你吗?看看你中了几点!
查看>>
为什么说程序员是“培训班出来的”就是鄙视呢?
查看>>
码农吐糟同事:写代码低调点不行么?空格回车键与你有仇吗?
查看>>
阿里p8程序员四年提交6000次代码的确有功,但一次错误让人唏嘘!
查看>>
一道技术问题引起的遐想,最后得出结论技术的本质是多么的朴实!
查看>>
985硕士:非科班自学编程感觉还不如培训班出来的,硕士白读了?
查看>>
你准备写代码到多少岁?程序员们是这么回答的!
查看>>
码农:和产品对一天需求,产品经理的需求是对完了,可我代码呢?
查看>>