SpringApplication.run(SpringEventApplication.class, args);
public static ConfigurableApplicationContext run(Object source, String... args) {
return run(new Object[] { source }, args);
}
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
return new SpringApplication(sources).run(args);
}
new SpringApplication()
public SpringApplication(Object... sources) {
initialize(sources);
}
private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
this.webEnvironment = deduceWebEnvironment();
//设置实现ApplicationContextInitializer接口的
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//设置实现ApplicationListener接口的
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
deduceWebEnvironment(推导环境)
private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" };
private boolean deduceWebEnvironment() {
for (String className : WEB_ENVIRONMENT_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return false;
}
}
return true;
}
setInitializers(Collection<? extends ApplicationContextInitializer<?>> initializers) 设置初始化
setInitializers(
(Collection)
getSpringFactoriesInstances(ApplicationContextInitializer.class)
);
public void setInitializers(
Collection<? extends ApplicationContextInitializer<?>> initializers) {
this.initializers = new ArrayList<ApplicationContextInitializer<?>>();
this.initializers.addAll(initializers);
}
getSpringFactoriesInstances
SpringFactoriesLoader.loadFactoryNames --获取所有ApplicationListener实现类类名
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;
}
deduceMainApplicationClass 推到出main 函数的类名
//手工抛一个RuntimeException然后获得这个RuntimeException的StackTraceElement[],
//迭代每个StackTraceElement从中找出methodName为main的那一个的className。
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;
以上
SpringApplication构造函数的主要作用
- initialize(sources)
- 判断是否是webEnvironment
- 设置实现ApplicationContextInitializer接口的实现
- 设置实现ApplicationListener接口的实现
- 设置启动类的类名名字
run函数 究竟干了什么?
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
//打印Banner
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
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);
}
}
new DefaultApplicationArguments(args);
获取启动时传入参数 args (main方法传进来的参数)
并初始化为 ApplicationArguments 对象。
public DefaultApplicationArguments(String[] args) {
Assert.notNull(args, "Args must not be null");
this.source = new Source(args);
this.args = args;
}
prepareEnvironmentp(准备环境)
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 遍历调用所有SpringApplicationRunListener的environmentPrepared()的方法,告诉他们:“当前SpringBoot应用使用的Environment准备好了咯!”。
listeners.environmentPrepared(environment);
if (!this.webEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertToStandardEnvironmentIfNecessary(environment);
}
return environment;
}
//如果 environment 不为空,直接 get 到,否则创建
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
if (this.webEnvironment) {
//一般来说是走这里
return new StandardServletEnvironment();
}
return new StandardEnvironment();
}
protected void configureEnvironment(ConfigurableEnvironment environment,String[] args) {
configurePropertySources(environment, args);
configureProfiles(environment, args);
}
createApplicationContext 创建SpringBoot的应用上下文
context = createApplicationContext();
public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework."
+ "boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext";
private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" };
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
//因为我们是web开发环境,
//所以这里我们的web上下文是AnnotationConfigEmbeddedWebApplicationContext这个对象
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);
}
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");
load(context, sources.toArray(new Object[sources.size()]));
listeners.contextLoaded(context);
}
对context进行了预设置,设置了ResourceLoader和ClassLoader
暂时不清楚此方法 对应什么场景
/**
* Apply any relevant post processing the {@link ApplicationContext}. Subclasses can
* apply additional processing as required.
* @param context the application context
*/
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());
}
}
}
load(context, sources.toArray(new Object[sources.size()]));
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug(
"Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
BeanDefinitionLoader loader = createBeanDefinitionLoader(
getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
loader.load();
}
/**
* Get the bean definition registry.
* @param context the application context
* @return the BeanDefinitionRegistry if it can be determined
*/
private BeanDefinitionRegistry getBeanDefinitionRegistry(ApplicationContext context) {
if (context instanceof BeanDefinitionRegistry) {
return (BeanDefinitionRegistry) context;
}
if (context instanceof AbstractApplicationContext) {
return (BeanDefinitionRegistry) ((AbstractApplicationContext) context)
.getBeanFactory();
}
throw new IllegalStateException("Could not locate BeanDefinitionRegistry");
}
protected BeanDefinitionLoader createBeanDefinitionLoader(
BeanDefinitionRegistry registry, Object[] sources) {
return new BeanDefinitionLoader(registry, sources);
}
/**
* Create a new {@link BeanDefinitionLoader} that will load beans into the specified
* {@link BeanDefinitionRegistry}.
* @param registry the bean definition registry that will contain the loaded beans
* @param sources the bean sources
*/
BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
Assert.notNull(registry, "Registry must not be null");
Assert.notEmpty(sources, "Sources must not be empty");
this.sources = sources;
this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
this.xmlReader = new XmlBeanDefinitionReader(registry);
//判断是否是 Groovy 环境
if (isGroovyPresent()) {
this.groovyReader = new GroovyBeanDefinitionReader(registry);
}
this.scanner = new ClassPathBeanDefinitionScanner(registry);
this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
}
private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
refreshContext(context) 方法又调用了 refresh(context)。在调用了 refresh(context) 方法之后,调用了 registerShutdownHook 方法。继续看它的 refresh 方法:
public void registerShutdownHook() {
if (this.shutdownHook == null) {
// No shutdown hook registered yet.
this.shutdownHook = new Thread() {
@Override
public void run() {
synchronized (startupShutdownMonitor) {
doClose();
}
}
};
Runtime.getRuntime().addShutdownHook(this.shutdownHook);
}
}
AnnotationConfigEmbeddedWebApplicationContext
这个类继承了EmbeddedWebApplicationContext类,GenericWebApplicationContext类(这个要注意),
它还实现了BeanDefinitionRegistry这个接口,还实现了ResourceLoader这个接口,
这个类可以说是一个全能类了,这个个类我们先不多说,主要是看它的父类EmbeddedWebApplicationContext这个类。
在这个类中重写了refresh方法、onRefresh方法、onClose方法、finishRefresh方法。这里我们先看onRefresh这个方法,
@Override
protected void onRefresh() {
//调用父类的onRefresh方法(GenericWebApplicationContext)
super.onRefresh();
try {
//创建嵌入式的Servlet容器
createEmbeddedServletContainer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start embedded container",
ex);
}
}
createEmbeddedServletContainer这个方法。
private void createEmbeddedServletContainer() {
//先获取embeddedServletContainer
EmbeddedServletContainer localContainer = this.embeddedServletContainer;
//获取Servlet上下文
ServletContext localServletContext = getServletContext();
//EmbeddedWebApplicationContext没有为EmbeddedServletContainer和ServletContext赋初值,也之前也没有调用set方法,所以这里都是为null
if (localContainer == null && localServletContext == null) {
//获取EmbeddedServletContainerFactory的实例 1)
EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();
//获取EmbeddedServletContainer 2)
this.embeddedServletContainer = containerFactory
.getEmbeddedServletContainer(getSelfInitializer());
}
else if (localServletContext != null) {
try {
getSelfInitializer().onStartup(localServletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context",
ex);
}
}
//初始化属性信息3)
initPropertySources();
}
1)处的代码:
protected EmbeddedServletContainerFactory getEmbeddedServletContainerFactory() {
// Use bean names so that we don't consider the hierarchy
//从BeanFactory中获取EmbeddedServletContainerFactory类型的Bean,这里没有考虑父BeanFactory
String[] beanNames = getBeanFactory()
.getBeanNamesForType(EmbeddedServletContainerFactory.class);
//如果没有获取到EmbeddedServletContainerFactory类型的Bean,则抛出异常
if (beanNames.length == 0) {
throw new ApplicationContextException(
"Unable to start EmbeddedWebApplicationContext due to missing "
+ "EmbeddedServletContainerFactory bean.");
}
//如果有一个以上的EmbeddedServletContainerFactory类型的Bean,则抛出异常
if (beanNames.length > 1) {
throw new ApplicationContextException(
"Unable to start EmbeddedWebApplicationContext due to multiple "
+ "EmbeddedServletContainerFactory beans : "
+ StringUtils.arrayToCommaDelimitedString(beanNames));
}
//从BeanFactory中获取EmbeddedServletContainerFactory类型的Bean
return getBeanFactory().getBean(beanNames[0],
EmbeddedServletContainerFactory.class);
}
1)代码意思
查看Spring容器中是否有EmbeddedServletContainerFactory类型的Bean,EmbeddedServletContainerFactory类型的Bean是否多于一个,从Spring容器中获取EmbeddedServletContainerFactory类型的Bean
-
EmbeddedServletContainerFactory 是什么呢?
从上图中我们可以看到,在SpringBoot中为我们内置了三种Web服务器的实现类,TomCat、Jetty、Undertow
- 那么EmbeddedServletContainerFactory的Bean是什么时候被注入到Spring容器中的呢?
- 这个类配置在spring.factories中,它的key为org.springframework.boot.autoconfigure.EnableAutoConfiguration,这里你需要知道,在SpringBoot启动的时候会加载这个类,并且这个类上带有Configuration这个注解,所以这个类会被注入到Spring容器中,然后这个类要生效还要有一个条件,即当前环境是web环境!在EmbeddedServletContainerAutoConfiguration中有这样的一段代码:
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication
@Import(BeanPostProcessorsRegistrar.class)
public class EmbeddedServletContainerAutoConfiguration {
@Configuration
@ConditionalOnClass({ Servlet.class, Tomcat.class })
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedTomcat {
@Bean
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
return new TomcatEmbeddedServletContainerFactory();
}
}
......
}
- 如果当前类路径下有Servlet和Tomcat这两个类,且在当前上下文中没有EmbeddedServletContainerFactory类型的Bean存在,则创建TomcatEmbeddedServletContainerFactory对象并注入到Spring容器中。SpringBoot中内置了TomCat相关的jar(spring-boot-starter-tomcat)。所以这里注入到Spring容器中的EmbeddedServletContainerFactory类型的Bean是
2)处的代码:
containerFactory
.getEmbeddedServletContainer(getSelfInitializer());
这里的containerFactory是TomcatEmbeddedServletContainerFactory的实例,所以这里调用的也是TomcatEmbeddedServletContainerFactory中的getEmbeddedServletContainer方法,
public EmbeddedServletContainer getEmbeddedServletContainer(
ServletContextInitializer... initializers) {
//创建一个TomCat对象
Tomcat tomcat = new Tomcat();
//创建web容器base目录
File baseDir = (this.baseDirectory != null ? this.baseDirector
: createTempDir("tomcat"));
tomcat.setBaseDir(baseDir.getAbsolutePath());
//创建一个连接器
Connector connector = new Connector(this.protocol);
//向tomcat的service中添加连接器
tomcat.getService().addConnector(connector);
//定制化Connector
customizeConnector(connector);
tomcat.setConnector(connector);
//自动部署设置为false
tomcat.getHost().setAutoDeploy(false);
//配置Engine
configureEngine(tomcat.getEngine());
//想tomcat中添加其他的Connector
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
//准备ServletContext的上下文
prepareContext(tomcat.getHost(), initializers);
//创建TomcatEmbeddedServletContainer
return getTomcatEmbeddedServletContainer(tomcat);
}
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);
}
}