博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring boot启动原理
阅读量:5020 次
发布时间:2019-06-12

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

1.入口类

/** * springboot应用的启动入口*/@RestController@SpringBootApplicationpublic class SampleApplication {        @RequestMapping("/")    public String sayhello(){        return "hello world";    }    public static void main(String[] args) {        // TODO Auto-generated method stub        SpringApplication.run(SampleApplication.class, args);    }}

 

Spring Boot程序的启动入口就一行代码,SpringApplication.run(SampleApplication.class,args)

2.执行过程

2.1SpringApplication的实例化

SpringApplication的静态run方法内部其实是new了一个SpringApplication的实例,构造函数保存了SourceClass。在SpringApplication实例初始化的时候,它做了几件事情:

  •  推断应用类型是standard还是Web。根据classpath里面是否存在某个特征类(org.springframework.web.context.ConfigurableWebApplicationContext)来决定是否应该创建一个为Web应用使用的ApplicationContext类型。
  • 使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationContextInitializer。SpringFactoriesLoader从类路径下各个jar的配置文件META-INF/spring.factories加载配置
  • 使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationListener。
  • 推断应用入口类

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 = deduceWebApplicationType(); setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }

 

下面具体从源码来看看每一步是怎么做的

2.1  推断应用类型是Standard还是Web

private WebApplicationType deduceWebApplicationType() {        if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)                && !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)) {            return WebApplicationType.REACTIVE;        }        for (String className : WEB_ENVIRONMENT_CLASSES) {            if (!ClassUtils.isPresent(className, null)) {                return WebApplicationType.NONE;            }        }        return WebApplicationType.SERVLET;    } //相关常量
 private static final String REACTIVE_WEB_ENVIRONMENT_CLASS = "org.springframework."
          + "web.reactive.DispatcherHandler";
 

 private static final String MVC_WEB_ENVIRONMENT_CLASS = "org.springframework."

          + "web.servlet.DispatcherServlet";

 

  private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",

         "org.springframework.web.context.ConfigurableWebApplicationContext" };

可能会出现三种结果:

  1. WebApplicationType.REACTIVE - 当类路径中存在REACTIVE_WEB_ENVIRONMENT_CLASS并且不存在MVC_WEB_ENVIRONMENT_CLASS时
  2. WebApplicationType.NONE - 也就是非Web型应用(Standard型),此时类路径中不包含WEB_ENVIRONMENT_CLASSES中定义的任何一个类时
  3. WebApplicationType.SERVLET - 类路径中包含了WEB_ENVIRONMENT_CLASSES中定义的所有类型时

2.2 设置初始化器ApplicationContextInitializer

setInitializers((Collection) getSpringFactoriesInstances(                ApplicationContextInitializer.class));

这里出现了一个新的概念 - 初始化器。

private 
Collection
getSpringFactoriesInstances(Class
type) { return getSpringFactoriesInstances(type, new Class
[] {}); }// 这里的入参type就是ApplicationContextInitializer.classprivate
Collection
getSpringFactoriesInstances(Class
type, Class
[] parameterTypes, Object... args) { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // Use names and ensure unique to protect against duplicates Set
names = new LinkedHashSet<>( SpringFactoriesLoader.loadFactoryNames(type, classLoader)); List
instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; }

这里面首先会根据入参type读取所有的names(是一个String集合),然后根据这个集合来完成对应的实例化操作。

// 这里的入参type就是ApplicationContextInitializer.class
public static List
loadFactoryNames(Class
factoryClass, @Nullable ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList()); } private static Map
> loadSpringFactories(@Nullable ClassLoader classLoader) { MultiValueMap
result = cache.get(classLoader); if (result != null) return result; try { Enumeration
urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); result = new LinkedMultiValueMap<>(); while (urls.hasMoreElements()) { URL url = urls.nextElement(); UrlResource resource = new UrlResource(url); Properties properties = PropertiesLoaderUtils.loadProperties(resource); for (Map.Entry
entry : properties.entrySet()) { List
factoryClassNames = Arrays.asList( StringUtils.commaDelimitedListToStringArray((String) entry.getValue())); result.addAll((String) entry.getKey(), factoryClassNames); } } cache.put(classLoader, result); return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } }

/**

* The location to look for factories.
* <p>Can be present in multiple JAR files.
*/
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

 

这个方法会尝试从类路径的META-INF/spring.factories处读取相应配置文件,然后进行遍历,读取配置文件中Key为:org.springframework.context.ApplicationContextInitializer的value。以spring-boot-autoconfigure这个包为例,它的META-INF/spring.factories部分定义如下所示:

# Initializersorg.springframework.context.ApplicationContextInitializer=\org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\ org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer

因此这两个类名会被读取出来,然后放入到集合中,准备开始下面的实例化操作:

private 
List
createSpringFactoriesInstances(Class
type, Class
[] parameterTypes, ClassLoader classLoader, Object[] args, Set
names) { List
instances = new ArrayList<>(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.context.ApplicationContextInitializer的子类,然后就是得到构造器进行初始化最后放入到实例列表中。

因此,所谓的初始化器就是org.springframework.context.ApplicationContextInitializer的实现类,这个接口是这样定义的:

public interface ApplicationContextInitializer
{ /** * Initialize the given application context. * @param applicationContext the application to configure */ void initialize(C applicationContext);}

根据类文档,这个接口的主要功能是:

在Spring上下文被刷新之前进行初始化的操作。典型地比如在Web应用中,注册Property Sources或者是激活Profiles。Property Sources比较好理解,就是配置文件。Profiles是Spring为了在不同环境下(如DEV,TEST,PRODUCTION等),加载不同的配置项而抽象出来的一个实体。

2.3 设置监听器ApplicationListener

setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 这里的入参type是:org.springframework.context.ApplicationListener.class private 
Collection
getSpringFactoriesInstances(Class
type) { return getSpringFactoriesInstances(type, new Class
[] {}); } private
Collection
getSpringFactoriesInstances(Class
type, Class
[] parameterTypes, Object... args) { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // Use names and ensure unique to protect against duplicates Set
names = new LinkedHashSet<>( SpringFactoriesLoader.loadFactoryNames(type, classLoader)); List
instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; }

 

可以发现,这个加载相应的类名,然后完成实例化的过程和上面在设置初始化器时如出一辙,同样,还是以spring-boot-autoconfigure这个包中的spring.factories为例,看看相应的Key-Value:

# Application Listenersorg.springframework.context.ApplicationListener=\org.springframework.boot.autoconfigure.BackgroundPreinitializer

至于ApplicationListener接口,它是Spring框架中一个相当基础的接口了,代码如下:

   

@FunctionalInterfacepublic interface ApplicationListener
extends EventListener { /** * Handle an application event. * @param event the event to respond to */ void onApplicationEvent(E event);}

2.4  推断应用入口类

this.mainApplicationClass = deduceMainApplicationClass();

这个方法的实现有点意思:

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

它通过构造一个运行时异常,通过异常栈中方法名为main的栈帧来得到入口类的名字。

至此,对于SpringApplication实例的初始化过程就结束了。

2.2  执行SpringApplication实例的run方法

SpringApplication实例的run方法内部都做了哪些呢:

1.创建SpringApplication自己的SpringApplicationRunListener。遍历执行所有通过SpringFactoriesLoader可以查找到并加载的SpringApplicationRunListener。调用.它们的started()方法,告诉这些SpringApplicationRunListener,“嘿,SpringBoot应用要开始执行咯!”。

2.创建并配置当前Spring Boot应用将要使用的Environment(包括配置要使用的PropertySource以及Profile)。

3. 遍历调用所有SpringApplicationRunListener的environmentPrepared()的方法,告诉他们:“当前SpringBoot应用使用的Environment准备好了咯!”。

4. 如果SpringApplication的showBanner属性被设置为true,则打印banner。

5.创建ApplicationContext,因为现在应用类型是Servlet,创建的是AnnotationConfigServletWebServerApplicationContext。

6.对ApplicationContext进行配置,将之前准备好的Environment设置给创建好的ApplicationContext使用。还有配置BeanNameGenerator、ResourceLoader等。

7.ApplicationContext创建好之后,然后遍历ApplicationContextInitializer的initialize(applicationContext)方法来对已经创建好的ApplicationContext进行进一步的处理。这里的ApplicationContextInitializer就是创建SpringApplication实例时设置的初始化器。

8. 遍历调用所有SpringApplicationRunListener的contextPrepared()方法。

9. 最核心的一步,将之前通过@EnableAutoConfiguration获取的所有配置以及其他形式的IoC容器配置加载到已经准备完毕的ApplicationContext。

10.遍历调用所有SpringApplicationRunListener的contextLoaded()方法。

11.启动ApplicationContext,AnnotationConfigServletWebServerApplicationContext继承了SpringFrameWork本身提供的GenericWebApplicationContext提供的功能并进行了扩展,以支持配置并启动Embed Tomcat。

             (1)、对BeanFactory进行一些初始化配置。

     (2)、执行BeanFactoryPostProcessor,其中包括对BeanDefinition的进一步处理。最重要的是ConfigurationClassPostProcessor,用来解析处理所有@Configuration标签类,并将Bean定义注册到BeanFactory中。因为@SpringBootApplication中包含了@EnableAutoConfiguration的meta-annotation,会进行自动配置处理,基本原理是判断工程依赖了哪些第三方组件并对其进行自动化配置,这样处理完@Configuration标签后,BeanFactory中就已经有大量的Bean定义了。

    (3)、注册BeanPostProcessor,这些Processor会在首次getBean时执行。主要功能包括进行Autowire、Required等标签的处理,完成自动绑定等功能。也有特殊的关于WebServleterFactory的后续处理。

    (4)、在ApplicationContext的onRefresh方法中会对Web容器(Tomcat)进行配置,包括注册Servlet、Filter、Listener等。

    (5)、在ApplicationContext的finishRefresh方法中启动Web容器(Tomcat),完成应用的启动。

3. 总结

 

转载于:https://www.cnblogs.com/whx7762/p/7834485.html

你可能感兴趣的文章
ORA-12538: TNS: no such protocol adapter
查看>>
盒子模型
查看>>
局域网协议
查看>>
[HNOI2012]永无乡 线段树合并
查看>>
Spring整合hibernate:3、使用XML进行声明式的事务管理
查看>>
SqlServer之Convert 函数应用格式化日期(转)
查看>>
软件测试领域中的10个生存和发展技巧
查看>>
Camera前后摄像头同时预览
查看>>
HDU 1856
查看>>
课堂作业01--架构师的职责
查看>>
iOS计算富文本(NSMutableAttributedString)高度
查看>>
2017/09/15 ( 框架2)
查看>>
SQL中join的用法
查看>>
dapper使用时性能优化
查看>>
【从数据库反向生成实体类】
查看>>
mybatis 批量更新 报错
查看>>
start WampServer如何关闭浏览目录
查看>>
PAT 甲级 1007 Maximum Subsequence Sum
查看>>
#Leetcode# 3. Longest Substring Without Repeating Characters
查看>>
HDU 2014 青年歌手大奖赛_评委会打分
查看>>