SpringBoot打包机制

先看一眼spring-boot的maven插件打包后的target目录:

其中有一个.jar.original的文件,一个.jar文件,其中.jar.original才是原始的jar包,而.jar文件是经过spring-boot的maven插件处理过后的jar,springboot的maven插件会将原始jar重命名成.jar.original,然后按springboot自己的规范打出一个可执行的jar包。

将该jar包重命名成.zip文件后打开即可看到文件中的内容:

可以看到,springboot执行的jar并不是一个java标准的jar,其中包含了springboot自身定义的内容。我们再打开其中的META-INF/MANIFEST.MF文件,看看其中指定的内容:

Main-Class是其中的启动类,springboot打包出来的jar,启动类并不是工程中包含main方法的启动类,而是springboot自己的JarLauncher类,而工程中定义的启动类在这里变成了Start-Class,由此也可以看出springboot应用在IDE里通过main方法运行与通过java -jar命令运行的区别。

SpringBoot应用的启动

打开springboot的Main-Class JarLauncher类,其中包含main方法:

这是springboot启动的入口,JarLauncher类继承自ExecutableArchiveLauncher类,进入到launch方法可以看到springboot有一个archive的概念,archive是归档的意思,springboot打出来的jar包就是一个archive。

ExecutableArchiveLauncher类的createArchive方法可以看到启动时的archive创建,通过当前类找到jar包的路径,并创建JarFileArchive:

通过getNestedArchives方法可以看到Archive是一个递归的概念,JarFileArchive中可以有其它嵌套的Archive:

在launch方法中,有getClassPathArchives方法的调用,此方法中调用了前面的getNestedArchives方法,传入的Filter是lambda表达式,通过isNestedArchive方法对JarFileArchive中的Entry做过滤:

可以得知,springboot打出的archive jar包中,ROOT-INF/classes/目录被认为是一个嵌套的Archive,ROOT-INF/lib/下的每一个jar包也被认为是一个Archive

因为springboot的archive不是一个标准的jar包,java提供的ClassLoader无法加载到archive中的依赖以及class,springboot提供了新的classloader的实现用来做Archive中类的加载:

可以看到springboot使用的是LaunchedURLClassLoader这个ClassLoader做的类的加载。创建好类加载器后,需要调用Start-Class,即应用中的main方法:

MainMethodRunner.run方法非常简单,逻辑是通过反射调用应用的main:

这一步之后,进入到了应用代码中。

SpringBoot应用初始化

在使用spring boot时,我们在main方法中调用SpringApplication.run进行初始化:

在SpringApplication.run方法中做了Spring的初始化:

可以清晰的看到spring的初始化。创建ApplicationContext对象使用的是createApplicationContext方法,此方法实现如下:

对于非WEB应用,使用的ApplicationContext的实例是DEFAULT_CONTEXT_CLASS,此常用定义为AnnotationConfigApplicationContext类,在依赖注入中提到的这个类,此类用于实现注解配置的ApplicationContext。

回到启动类,启动类上加了一个@SpringBootApplication注解,此注解的定义:

前面Annotation的解析机制中提到,spring能通过解析@ComponentScan注解注册bean,但是springboot中,@ComponentScan标识在SpringBootApplication注解上,AnnotationConfigApplicationContext是定义在spring-context包中的,而@SpringBootApplication是定义在spring-boot-autoconfig中的注解,spring-context包并不依赖于spring-boot-autoconfig包,AnnotationConfigApplicationContext能通过@SpringBootApplication注解完成初始化是因为spring的注解处理工具类能识别出@SpringBootApplication的元注解@ComponentScan以及@AliasFor注解标识 的属性,实现逻辑在spring-core包中的AnnotationConfigUtils类中。

最后看看SpringApplication类的构造器:

在getSpringFactoriesInstances方法中,使用了SpringFactoriesLoader:

打开spring-boot相关的包,能看到spring.factories文件:

SpringFactoriesLoader是spring-core中提供的类,用于处理spring.factories文件,SpringFactoriesLoader.loadFactoryNames方法会读取类路径下的所有META-INF/spring.factories文件:

AutoConfiguration

回到@SpringBootApplication注解的定义:

其注解上被标记了@EnableAutoConfiguration注解,此注解用于实现autoconfiguration。打开此注解可以看到它实际上是使用了注解解析机制中的@Import注解:

如何使用ImportSelector就回到了@Import的处理逻辑中(见前面的文章)。可以看到,实现autoconfiguration的入口正是这个EnableAutoConfigurationImportSelector类,此类的selectImports方法返回的是需要作为配置类的类,这里的具体作用就是拿到类路径下的所有的自动配置的类,其代码实现:

AutoConfigurationMetadataLoader.loadMetadata方法的实现比较简单

即从META-INF/spring-autoconfigure-metadata.properties文件中加载数据,此文件在classpath下可以有多个(每个jar包中都可以有一个),随便打开一个配置文件,看看其中的内容:

里面都是一些配置类。@Import将这些配置类导入给spring的注解处理器ConfigurationClassParser就完成了bean的配置。

另外,在@SpringBootApplication注解上,还标记了一个@ComponentScan注解,其中的excludeFilters中有一个是AutoConfigurationExcludeFilter:

此类会判断如果class标了@Configuration并且此类包含spring.factories文件中,则在处理@Configuration注解时排除此类:

上面的代码中,getAutoConfigurations方法是从SpringFactoriesLoader中取的EnableAutoConfiguration关联的类。

maven springboot 除去指定的jar包_SpringBoot的运行机制相关推荐

  1. maven springboot 除去指定的jar包_1. Spring Boot概述

    1.1 Spring Boot理解 Spring Boot来简化Spring应用开发,约定大于配置,去繁从简,just run就能创建一个独立的,产品级别的应用 背景 J2EE笨重的开发.繁多的配置. ...

  2. maven springboot 除去指定的jar包_Spring Boot打包瘦身 Docker 使用全过程 动态配置、日志记录配置...

    springBoot打包的时候代码和jar包打包在同一个jar包里面,会导致jar包非常庞大,在不能连接内网的时候调试代码,每次只改动了java代码就需要把所有的jar包一起上传,导致传输文件浪费了很 ...

  3. java生成cmd jar包_Java程序运行机制及cmd编译运行探究(二) cmd编译运行Java程序并打成jar包...

    目标:写一个RandomUtils.java工具类,返回一个随机数,并把这个类的字节码文件打成jar包 在Java运行机制及cmd编译运行探究(一)准备工作一文中,我总结了一部分要用到的cmd及编译运 ...

  4. srtp项目中关于引入Maven仓库中指定版本jar包的一些问题

    文章目录 背景 问题 解决方案 打开Maven的搜索 搜索网址打开之后,直接将你想要查找的jar包全名输进去即可,类似于向下面这样. 指定之后仍然代码出错 背景 相信很多和我一样刚入门的新人对于另外一 ...

  5. springboot基于mybatis扫描jar包中的controller、service、dao、xml

    springboot基于mybatis扫描jar包中的controller.service.dao.xml 最近有这样的需求,是将某个业务模块接口,比如新闻的接口模块 作为一个公共固定的模块,整个包括 ...

  6. java配置pom安装依赖包,Maven pom.xml 添加本地jar包依赖以及打包方法

    Maven项目打包时,如果遇到需要添加本地jar包依赖的时候,可以选择两种方法: 1. 安装到本地仓库 第一种方法比较常规,适用于需要添加的jar包也是由maven项目导出,含有pom文件的时候.只需 ...

  7. IDEA把Springboot打成可执行jar包,内嵌tomcat 这个可以用

    IDEA把Springboot打成可执行jar包,内嵌tomcat 2018年11月23日 18:36:30 ta山之石可以攻玉 阅读数 3061 版权声明:本文为博主原创文章,未经博主允许不得转载. ...

  8. maven导出Java方法_eclipse导出maven工程的可执行jar包

    一.eclipse导出maven工程的可执行jar包 建立两个maven工程 ZKServer 和ZKClient 注意:用maven进行开发管理的话,默认的打出来的jar包是不能运行的,需要在pom ...

  9. maven打包可执行的jar包-包含依赖jar

    maven打包可执行的jar包: 1. 首先确保编辑器里maven环境正常 2. 运行打包的jar文件 3. 测试添加依赖后打包. 4. Unable to access jarfile test-m ...

最新文章

  1. USEARCH11命令大全,200+命令中文简介,快速查找需要功能
  2. Web.config文件使用
  3. 汇编-函数调用的理解
  4. prop和attr在 jquery的
  5. python爬虫运行不出结果_请问这个为什么就是爬不到,运行之后电脑卡的不行,求大佬指导...
  6. 你知道哪些情况下不该使用深度学习吗?
  7. 力扣455. 分发饼干(JavaScript)
  8. 2016年最酷的十大安全初创公司
  9. 阿里巴巴(容器镜像服务)docker+springboot实践
  10. HDU 1863 (图论基础prim算法)
  11. 创建一个字体wx.Font
  12. Git教程之如何版本回退
  13. 学习笔记 - 大数据导论
  14. Pycharm使用tkinter
  15. 上地服务器托管机房的现状
  16. 基于MCR的MATLAB使用案例
  17. FreeSwitcch(java使用)
  18. 用友u8文件服务器备份,用友u8 数据备份到云服务器
  19. mysql格式化去掉千分号_SQL 格式化数字,千分位分隔符并保留2位小数
  20. 大疆口袋灵眸发布(OSMO Pocket)

热门文章

  1. MapReduce计数器
  2. Linux 常用的帮助命令
  3. Spyder kernel died 错误
  4. .NET面试题解析(04)-类型、方法与继承
  5. 题目1065:输出梯形
  6. FatMouse's Speed hdu 1160(动态规划,最长上升子序列+记录路径)
  7. 精通android(Pro Android 4)面试题总结(一)
  8. @jsonignore的作用
  9. 炎炎夏日需要一个清凉的地 - 自制水冷系统(十一 指尖的思绪之程序篇)
  10. LINQ是死是活?——很奇怪为什么会有这样的话题?