ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Springboot启动流程(新手向)1:初步加载所有类

2021-09-14 16:58:56  阅读:266  来源: 互联网

标签:Springboot 子类 classLoader spring 新手 class 加载


前情提要:

本次使用2.5.2版本Springboot

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.2</version>
    </parent>

1.一个普通的Springboot启动类

 

2.进入SpringApplication.run方法查看

 

 

3.

先看SpringApplication 构造方法

 

 

 其中

primarySources 就是 第一张图里写的 Example.class

4.

查看上面第一个getBootstrapRegistryInitializersFromSpringFactories

 

 

5.

查看第2步Spring工程加载器加载类做了哪些操作

 SpringFactoriesLoader.loadFactoryNames

 

6.查看loadSpringFactories加载了什么类

 

看一看cache是啥

 

 简单讲一下classLoader

classLoader有三种:

1.Bootstrap loader

 用C++写的,加载%JAVA_HOME%/jre/lib,-Xbootclasspath参数指定路径%JAVA_HOME%/jre/classes

 可以简单的认为,使java运行起来就是靠这个类加载器,程序员接触不到。

2.ExtClassLoader 

Bootstrp loader加载。 类名:sun.misc.Launcher$ExtClassLoader

主要加载%JAVA_HOME%/jre/lib/ext,此路径下的所有classes目录以及java.ext.dirs系统变量指定的路径中类库。程序员也接触不到。

3.AppClassLoader Launcher$AppClassLoader (程序员使用的这个加载器)

由1.Bootstrap loader加载,但是它会将父类指定为2.ExtClassLoader 

 由上图可以看到继承关系,Bootstrap不存在,因为它是C++写的,负责加载能使Java运行的关键类。

AppClassLoader就是我们做项目,写代码时,所使用的加载类。

6.1

继续查看loadSpringFactories加载了什么类

 

此次是第一次加载,所以代码继续运行

 

 

 在这里,要简单测试一下classLoader.getResources的方法

 准备一个jar包,在META-INF 下 有spring.factories,内容如下

I.am.the.jar=\
jar.test.one,\
jar.test.two,\
jar.test.three

数据格式说一下 :

=\代表这是个根节点,这是一个父类,后面跟着的都是子类了

,\表示后面还有节点

只有类名,后面没有跟符号,说明当前父类已经结束

在项目下也有一个相同目录,相同的文件

 内容如下:

we.are.class=\
class.one,\
class.two,\
class.three

 有以下代码(结合运行结果看):

ClassLoader classLoader = ClassLoadTest.class.getClassLoader();
Enumeration<URL> urls = classLoader.getResources("META-INF/spring.factories");
while (urls.hasMoreElements()) {
       URL url = urls.nextElement();
       UrlResource resource = new UrlResource(url);
       Properties properties = PropertiesLoaderUtils.loadProperties(resource);
       for (Map.Entry<Object, Object> entry : properties.entrySet()) {
           System.out.println(entry.getKey());
           System.out.println(entry.getValue());
           String[] factoryImplementationNames =
                StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
           System.out.println(Arrays.toString(factoryImplementationNames));
     }
  }

 运行:

 所以,我们知道了加载配置文件的功能。

在SpringBoot中,通过加载配置文件,将它所需的类都给加载进来。

这些只是其中之一。

 

我们也可以实现自己的context类,filter类等等,让Springboot进行管理

 

 

 

6.2

继续查看loadSpringFactories加载了什么类

result.computeIfAbsent 用法,如果当前factoryTypeName不存在,则 key -> new ArrayList<>() 生成一个新的ArrayList做value, key 是 factoryTypeName

然后将子类放到list中去

add(factoryImplementationName.trim());

 

最后cache用classLoader,即AppClassLoader作为key,去存放spring.factories里的类信息

 

 7.加载完spring.factories之后做了什么

 

 

 

 由此我们可知

getSpringFactoriesInstances,就是获取当前class下,在spring.factories里有没有配置一些子类,如果配置了,则将这些子类实例化,放到springboot中。

8.具体放到springboot的操作

 

 

getBootstrapRegistryInitializersFromSpringFactories 获取到
Bootstrapper.classBootstrapRegistryInitializer.class 两个配置子类实例(如果有的话)。

 并且都放进了springboot的 bootstrapRegistryInitializers 参数中。

 而 获取 ApplicationContextInitializer.class的配置子类实例放到 initializers 中

 获取  ApplicationListener.class 的配置子类实例放到  listeners 中

 

9.判断入口类(运行主类,Springboot主类,main方法所在的类)

 

测试:

 

 

运行结果:

 

是谁调用的都可以看到。

而main方法在Springboot只存在一个,所以可以查到这个主入口类。

不过奇怪的是,主入口类里面的参数class,必须是当前类,为什么还要有这个判断。

 就当留着一个小疑问。

至此,springboot的构造方法已经全部跑完。

下一篇,将讲解构造完之后的run方法。

 

 

 

 

 

 

 

 

 

 

 

标签:Springboot,子类,classLoader,spring,新手,class,加载
来源: https://blog.csdn.net/liu538430/article/details/120287231

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有