springboot学习7

SpringApplication
1、SpringApplication基本使用:
1.1 SpringApplication运行

SpringApplication.run(DemoSpringBootApplication.class, args)

1.2、自定义SpringApplication
1)通过SpringApplicationAPI 方式

SpringApplication springApplication = new SpringApplication(DemoSpringBootApplication.class);
springApplication.setBannerMode(Banner.Mode.CONSOLE);
springApplication.setWebApplicationType(WebApplicationType.NONE);
springApplication.setAdditionalProfiles("prod");
springApplication.setHeadless(true);

2)通过SpringApplicationBuilderAPI 方式

new SpringApplicationBuilder(DemoSpringBootApplication.class)    
	.bannerMode(Banner.Mode.CONSOLE)   
 	.web(WebApplicationType.NONE)   
  	.profiles("prod") 
  	.headless(true)
  	.run(args);

2、SpringApplication准备阶段:

package org.springframework.boot;

public class SpringApplication {
    
    

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 = WebApplicationType.deduceFromClasspath();
		// 通过工厂方式,加载实例。在后面的运行阶段(run方法)来操作。
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
		// 通过工厂方式,加载实例。在后面的运行阶段(run方法)来操作。
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		// 推断当前主类,通过线程的栈来推断。
		this.mainApplicationClass = deduceMainApplicationClass();
	}
}

2.1 配置 Spring Boot Bean 源

Java 配置 Class 或 XML 上下文配置文件集合,用于 `Spring Boot BeanDefinitionLoader`读取,并且将配置源解析加载为Spring Bean 定义
package org.springframework.boot;

class BeanDefinitionLoader {
    
    
	//...省略
	// bean定义注册, 一个或多个
	BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
    
    
			Assert.notNull(registry, "Registry must not be null");
			Assert.notEmpty(sources, "Sources must not be empty");
			this.sources = sources;
			// java class或者bean或者 xml
			this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
			this.xmlReader = new XmlBeanDefinitionReader(registry);
			if (isGroovyPresent()) {
    
    
				this.groovyReader = new GroovyBeanDefinitionReader(registry);
			}
			this.scanner = new ClassPathBeanDefinitionScanner(registry);
			this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
	}
}

配置 Class

Java 配置 Class用于 Spring 注解驱动中 Java 配置类,大多数情况是 Spring 模式注解所标注的类,如`@Configuration`。
XML 上下文配置文件用于 Spring 传统配置驱动中的 XML 文件。

XML 上下文配置文件

package com.example.springbootlearn.demospringboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * {@link SpringApplication}
 *
 */
@SpringBootApplication
public class SpringApplicationBootstrap {
    
    

    public static void main(String[] args) {
    
    
        SpringApplication.run(SpringApplicationBootstrap.class, args);
    }
}

在SpringApplication的run方法中,要传入标了@SpringBootApplication的类。不一定是主类。比如下面这样也可以:

package com.example.springbootlearn.demospringboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * {@link SpringApplication}
 *
 */
public class SpringApplicationBootstrap {
    
    

    public static void main(String[] args) {
    
    
        SpringApplication.run(ApplicationConfiguration.class, args);
    }

    @SpringBootApplication
    public static class ApplicationConfiguration {
    
    

    }
}

也可以这样:

package com.example.springbootlearn.demospringboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.util.HashSet;
import java.util.Set;

/**
 * {@link SpringApplication}
 *
 */
public class SpringApplicationBootstrap {
    
    

    public static void main(String[] args) {
    
    
//        SpringApplication.run(ApplicationConfiguration.class, args);

        Set<String> sources = new HashSet<>();
        sources.add(ApplicationConfiguration.class.getName());
        SpringApplication springApplication = new SpringApplication();
        springApplication.setSources(sources);
        springApplication.run(args);
    }

    @SpringBootApplication
    public static class ApplicationConfiguration {
    
    

    }
}

setSources方法:

package org.springframework.boot;
public class SpringApplication {
    
    
	// ...省略
	
	/**
	 * Set additional sources that will be used to create an ApplicationContext. A source
	 * 可以是:
	 * can be: a class name, package name, or an XML resource location.
	 * <p>
	 * Sources set here will be used in addition to any primary sources set in the
	 * constructor.
	 * @param sources the application sources to set
	 * @see #SpringApplication(Class...)
	 * @see #getAllSources()
	 */
	public void setSources(Set<String> sources) {
    
    
		Assert.notNull(sources, "Sources must not be null");
		this.sources = new LinkedHashSet<>(sources);
	}
}

2.2 推断 Web 应用类型
根据当前应用 ClassPath 中是否存在相关实现类来推断 Web 应用的类型,包括:

Web Reactive:WebApplicationType.REACTIVE
Web Servlet:WebApplicationType.SERVLET
非 Web:WebApplicationType.NONE

推断方法:

package org.springframework.boot.test.context;

public class SpringBootTestContextBootstrapper extends DefaultTestContextBootstrapper {
    
    
	// ... 省略
	
	private WebApplicationType deduceWebApplicationType() {
    
    
			if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null) // REACTIVE_WEB_ENVIRONMENT_CLASS = "org.springframework." + "web.reactive.DispatcherHandler";
					&& !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null) // MVC_WEB_ENVIRONMENT_CLASS = "org.springframework." + "web.servlet.DispatcherServlet";
					&& !ClassUtils.isPresent(JERSEY_WEB_ENVIRONMENT_CLASS, null)) {
    
     // JERSEY_WEB_ENVIRONMENT_CLASS = "org.glassfish.jersey.server.ResourceConfig";
				return WebApplicationType.REACTIVE;
			}
			for (String className : WEB_ENVIRONMENT_CLASSES) {
    
    
				if (!ClassUtils.isPresent(className, null)) {
    
    
					return WebApplicationType.NONE;
				}
			}
			return WebApplicationType.SERVLET;
	}
}

2.3 推断引导类(Main Class):

package org.springframework.boot;

public class SpringApplication {
    
    

// ... 省略

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

2.4 加载应用上下文初始器ApplicationContextInitializer
通过Spring 工厂加载机制,实例化 ApplicationContextInitializer 实现类,并排序对象集合。

package org.springframework.boot;

public class SpringApplication {
    
    
	// ... 省略

	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
				Class<?>[] parameterTypes, Object... args) {
    
    
			ClassLoader classLoader = getClassLoader();
			// 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;
	}
}

上面代码中:SpringFactoriesLoader.loadFactoryNames方法,

  • 通过类: org.springframework.core.io.support.SpringFactoriesLoader实现。
  • 会去读取配置资源: META-INF/spring.factories
  • 排序: AnnotationAwareOrderComparator.sort(instances)

参考:
在org.springframework.boot.autoconfigure的spring.factories中,可以看到应用上下文初始配置。
在这里插入图片描述

自定义:
在resources目录下新建META-INF文件,在META-INF下新建spring.factories文件。

在这里插入图片描述
spring.factories

# 实际顺序与order有关,与这里配置顺序无关。
# Initializers
org.springframework.context.ApplicationContextInitializer=\
com.example.springbootlearn.context.AfterDemoApplicationContextInitializer,\
com.example.springbootlearn.context.DemoApplicationContextInitializer

新建content文件夹,新建DemoApplicationContextInitializer文件。

DemoApplicationContextInitializer

package com.example.springbootlearn.context;

import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

/**
 *
 */
@Order(Ordered.HIGHEST_PRECEDENCE)
public class DemoApplicationContextInitializer<C extends ConfigurableApplicationContext>  implements ApplicationContextInitializer<C> {
    
    

    @Override
    public void initialize(C applicationContext) {
    
    
        System.out.println("ConfigurableApplicationContext.id =  :" + applicationContext.getId());
    }
}

新建AfterDemoApplicationContextInitializer文件:

package com.example.springbootlearn.context;

import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Ordered;

public class AfterDemoApplicationContextInitializer implements ApplicationContextInitializer, Ordered {
    
    

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
    
    
        System.out.println("after applicationContext.id = " + applicationContext.getId());
    }

    @Override
    public int getOrder() {
    
    
        return Ordered.LOWEST_PRECEDENCE;
    }
}

SpringApplicationBootstrap

package com.example.springbootlearn.demospringboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.util.HashSet;
import java.util.Set;

/**
 * {@link SpringApplication}
 *
 */
public class SpringApplicationBootstrap {
    
    

    public static void main(String[] args) {
    
    
//        SpringApplication.run(ApplicationConfiguration.class, args);

        Set<String> sources = new HashSet<>();
        sources.add(ApplicationConfiguration.class.getName());
        SpringApplication springApplication = new SpringApplication();
        springApplication.setSources(sources);
        springApplication.setWebApplicationType(WebApplicationType.NONE);  // web和非web都会输出
        springApplication.run(args);
    }

    @SpringBootApplication
    public static class ApplicationConfiguration {
    
    

    }
}

运行结果:

// ... 省略
ConfigurableApplicationContext.id =  :org.springframework.context.annotation.AnnotationConfigApplicationContext@22702006
after applicationContext.id = application
// ... 省略

2.5 加载应用事件监听器( ApplicationListener)
通过Spring 工厂加载机制,实例化 ApplicationListener 实现类,并排序对象集合。
参考:
在这里插入图片描述

自定义:
创建listernr文件夹,在新建一个DemoApplicationListener类:

DemoApplicationListener

package com.example.springbootlearn.listener;

import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

/**
 *  Demo {@link ApplicationListener} 监听 {@link ContextRefreshedEvent}
 *
 */
@Order(Ordered.HIGHEST_PRECEDENCE)
public class DemoApplicationListener implements ApplicationListener<ContextRefreshedEvent> {
    
    
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
    
    
        System.out.println("demo ... : " + event.getApplicationContext().getId()
                + ",timestamp : " + event.getTimestamp());
    }
}

创建AfterDemoApplicationListener

package com.example.springbootlearn.listener;

import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.Ordered;


/**
 * After Demo {@link ApplicationListener} 监听 {@link ContextRefreshedEvent}
 */
public class AfterDemoApplicationListener implements ApplicationListener<ContextRefreshedEvent>, Ordered  {
    
    
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
    
    
        // #监听事件要一样 进行order排序
        System.out.println("after demo ... : " + event.getApplicationContext().getId()
                + ",timestamp : " + event.getTimestamp());
    }

    @Override
    public int getOrder() {
    
    
        return Ordered.LOWEST_PRECEDENCE;
    }
}

SpringApplicationBootstrap

package com.example.springbootlearn.demospringboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.util.HashSet;
import java.util.Set;

/**
 * {@link SpringApplication}
 *
 */
public class SpringApplicationBootstrap {
    
    

    public static void main(String[] args) {
    
    
//        SpringApplication.run(ApplicationConfiguration.class, args);

        Set<String> sources = new HashSet<>();
        sources.add(ApplicationConfiguration.class.getName());
        SpringApplication springApplication = new SpringApplication();
        springApplication.setSources(sources);
        springApplication.run(args);
    }

    @SpringBootApplication
    public static class ApplicationConfiguration {
    
    

    }
}

运行结果:

demo ... : application,timestamp : 1612591318234
after demo ... : application,timestamp : 1612591318234

3、SpringApplication 运行阶段
3.1 加载与运行SpringApplication 运行(run)监听器
main方法调用SpringApplication的run方法。
springApplication.run(args);

    public static void main(String[] args) {
    
    
//        SpringApplication.run(ApplicationConfiguration.class, args);

        Set<String> sources = new HashSet<>();
        sources.add(ApplicationConfiguration.class.getName());
        SpringApplication springApplication = new SpringApplication();
        springApplication.setSources(sources);
        springApplication.run(args);
    }

类:SpringApplication

package org.springframework.boot;

public class SpringApplication {
    
    
	//... 省略

	public ConfigurableApplicationContext run(String... args) {
    
    
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
		//  加载监听器。通过Spring 工厂加载机制,读取 SpringApplicationRunListener 对象集合
		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;
	}
}

SpringApplicationRunListener监听多个运行状态方法:

监听方法 阶段说明 Spring Boot Since版本
starting() Spring 应用刚启动 1.0
environmentPrepared(ConfigurableEnvironment) ConfigurableEnvironment 准备妥当,允许将其调整 1.0
contextPrepared(ConfigurableApplicationContext) ConfigurableApplicationContext 准备妥当,允许将其调整 1.0
contextLoaded(ConfigurableApplicationContext) ConfigurableApplicationContext 已装载,但仍未启动 1.0
started(ConfigurableApplicationContext) ConfigurableApplicationContext 已启动,此时 Spring Bean 已初始化完成 2.0
running(ConfigurableApplicationContext) Spring 应用正在运行 2.0
failed(ConfigurableApplicationContext,Throwable) Spring 应用运行失败 2.0

3.2 监听 事件
springboot 通过 SpringApplicationRunListener 的实现类 EventPublishingRunListener
通过 Spring Framework 事件,API 来广播 Spring Boot 事件。
1)spring事件

public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
    
    
// ... 省略

// 广播
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    
    
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
		for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
    
    
			Executor executor = getTaskExecutor();
			// 异步或同步
			if (executor != null) {
    
    
				executor.execute(() -> invokeListener(listener, event));
			}
			else {
    
    
				invokeListener(listener, event);
			}
		}
	}
}
Spring 应用事件
	普通应用事件: ApplicationEvent
	应用上下文事件: ApplicationContextEvent 
Spring 应用监听器
	接口编程模型: ApplicationListener
	注解编程模型: @EventListener 
Spring 应用事广播器
	接口: ApplicationEventMulticaster
	实现类: SimpleApplicationEventMulticaster

参考:
在spring-boot-2.1.0.RELEASE-sources.jar/META-INF/spring.factories文件中:
在这里插入图片描述
在这里插入图片描述
自定义一个:
在com.example.springbootlearn新建一个run包
新建一个DemoRunListener类:

package com.example.springbootlearn.run;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;

public class DemoRunListener implements SpringApplicationRunListener {
    
    

    public DemoRunListener(SpringApplication application, String[] args) {
    
    

    }

    @Override
    public void starting() {
    
    
        System.out.println("DemoRunListener:starting()......");
    }

    @Override
    public void environmentPrepared(ConfigurableEnvironment environment) {
    
    

    }

    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
    
    

    }

    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
    
    

    }

    @Override
    public void started(ConfigurableApplicationContext context) {
    
    

    }

    @Override
    public void running(ConfigurableApplicationContext context) {
    
    

    }

    @Override
    public void failed(ConfigurableApplicationContext context, Throwable exception) {
    
    

    }
}

运行结果:
发现比banner打印还早。

DemoRunListener:starting()......
banner打印
// ... 省略

这是因为SpringApplicationrun方法:

package org.springframework.boot;
public class SpringApplication {
    
    
	// ... 省略
	public ConfigurableApplicationContext run(String... args) {
    
    
		 // ...省略
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try{
    
    
		// ...省略
			Banner printedBanner = printBanner(environment);
		}
		// ...省略
	}
}

EventPublishingRunListener 监听方法与 Spring Boot 事件对应关系

监听方法 springboot 事件 springboot since版本
starting() ApplicationStartingEvent 1.5
environmentPrepared(ConfigurableEnvironment) ApplicationEnvironmentPreparedEvent 1.0
contextPrepared(ConfigurableApplicationContext)
contextLoaded(ConfigurableApplicationContext) ApplicationPreparedEvent 1.0
started(ConfigurableApplicationContext) ApplicationStartedEvent 2.0
running(ConfigurableApplicationContext) ApplicationReadyEvent 2.0
failed(ConfigurableApplicationContext,Throwable) ApplicationFailedEvent 1.0

2) 监听springboot事件
spring-boot-2.1.0.RELEASE.jar/META-INF/spring.factoires中,
在这里插入图片描述
参考:org.springframework.boot.context.config.ConfigFileApplicationListener

自定义:
在com.example.springbootlearn.listener包下,新建一个BeforeConfigFileApplicationListener文件。
BeforeConfigFileApplicationListener

package com.example.springbootlearn.listener;

import org.springframework.boot.context.config.ConfigFileApplicationListener;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.core.Ordered;
import org.springframework.core.env.Environment;

/**
 * before {@link ConfigFileApplicationListener} 实现
 */
public class BeforeConfigFileApplicationListener implements SmartApplicationListener, Ordered {
    
    
    // Order值越小,优先级越高。所以 这里 比 ConfigFileApplicationListener 优先级高
    @Override
    public int getOrder() {
    
    
        return ConfigFileApplicationListener.DEFAULT_ORDER - 1;
    }

    @Override
    public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
    
    
        return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType)
                || ApplicationPreparedEvent.class.isAssignableFrom(eventType);
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
    
    
        if (event instanceof ApplicationEnvironmentPreparedEvent) {
    
    
            ApplicationEnvironmentPreparedEvent preparedEvent = (ApplicationEnvironmentPreparedEvent)event;
            Environment environment = preparedEvent.getEnvironment();
            System.out.println("environment.getProperty(\"name\") :" + environment.getProperty("name"));
        }
        if (event instanceof ApplicationPreparedEvent) {
    
    

        }
    }
}

spring.factories

# Application Listeners
org.springframework.context.ApplicationListener=\
com.example.springbootlearn.listener.BeforeConfigFileApplicationListener

application.properties

name = learndemo

运行结果:

//... 省略
environment.getProperty("name") :null
// ... 省略

调整一下order值,将上面代码的order修改一下:

    @Override
    public int getOrder() {
    
    
        return ConfigFileApplicationListener.DEFAULT_ORDER + 1;
    }

运行输出:

// ...省略
environment.getProperty("name") :learndemo
// ...省略

3.3 创建 Spring 应用上下文

Web Reactive: AnnotationConfigReactiveWebServerApplicationContext // package org.springframework.boot.web.reactive.context;
Web Servlet: AnnotationConfigServletWebServerApplicationContext // package org.springframework.boot.web.servlet.context;
非 Web: AnnotationConfigApplicationContext  // package org.springframework.context.annotation;

参考:

package org.springframework.boot;

public class SpringApplication {
    
    
	public ConfigurableApplicationContext run(String... args) {
    
    
	// ...省略
	ConfigurableApplicationContext context = null;
	try {
    
    
		// ... 省略
		context = createApplicationContext();
		// ... 省略
	}
    // ... 省略
	}
}

createApplicationContext()

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

自定义:

package com.example.springbootlearn.demospringboot;

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;

/**
 * Spring 应用上下文 引导类
 */
@SpringBootApplication
public class SpringApplicationContextBootstrap {
    
    

    public static void main(String[] args) {
    
    
		
		// web servlet或web Reactive 或非web
        ConfigurableApplicationContext context = new SpringApplicationBuilder(SpringApplicationContextBootstrap.class)
                // .web(WebApplicationType.NONE) // web servlet或web Reactive 或非web
                .run(args);

        System.out.println("ConfigurableApplicationContext 类型:" +
                context.getClass().getName());

        // 关闭上下文
        context.close();
    }
}

运行结果:

web = WebApplicationType.SERVLET

// ... 省略
ConfigurableApplicationContext 类型:org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
// ... 省略

web = WebApplicationType.NONE


// ... 省略
ConfigurableApplicationContext 类型:org.springframework.context.annotation.AnnotationConfigApplicationContext
// ... 省略

web =WebApplicationType.REACTIVE

// ... 省略
ConfigurableApplicationContext 类型:org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext
// ... 省略

3.4 创建 Environment
根据准备阶段的推断 Web 应用类型创建对应的 ConfigurableEnvironment 实例:

Web Reactive: StandardEnvironment
Web Servlet: StandardServletEnvironment 
非 Web: StandardEnvironment
package com.example.springbootlearn.demospringboot;

import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;

/**
 * Spring 应用上下文 引导类
 */
@SpringBootApplication
public class SpringApplicationContextBootstrap {
    
    

    public static void main(String[] args) {
    
    

        ConfigurableApplicationContext context = new SpringApplicationBuilder(SpringApplicationContextBootstrap.class)               
             // .web(WebApplicationType.NONE) // web servlet或web Reactive 或非web
                .run(args);

        System.out.println("ConfigurableApplicationContext 类型:" +
                context.getClass().getName());
		// Environment
        System.out.println("Environment 类型:" +
                context.getEnvironment().getClass().getName());

        // 关闭上下文
        context.close();
    }
}

运行结果:
.web(WebApplicationType.NONE)


ConfigurableApplicationContext 类型:org.springframework.context.annotation.AnnotationConfigApplicationContext
Environment 类型:org.springframework.core.env.StandardEnvironment

.web(WebApplicationType.REACTIVE)

ConfigurableApplicationContext 类型:org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext
Environment 类型:org.springframework.boot.web.reactive.context.StandardReactiveWebEnvironment

.web(WebApplicationType.SERVLET)

ConfigurableApplicationContext 类型:org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
Environment 类型:org.springframework.web.context.support.StandardServletEnvironment

SpringApplication上下文周期来逐一调用,把相应的资源准备好。

package org.springframework.boot;

public class SpringApplication {
    
    
	// ... 省略
	
	// SpringApplication上下文周期来逐一调用,把相应的资源准备好。
	public ConfigurableApplicationContext run(String... args) {
    
    
		// ... 省略
		ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
		// ... 省略
	}
	
	private ConfigurableEnvironment prepareEnvironment(
		// ... 省略
		ConfigurableEnvironment environment = getOrCreateEnvironment();
		configureEnvironment(environment, applicationArguments.getSourceArgs());
		listeners.environmentPrepared(environment);	// 监听
		// ... 省略
	}
}

猜你喜欢

转载自blog.csdn.net/tongwudi5093/article/details/113705217