maven springboot 除去指定的jar包_SpringBoot的运行机制

SpringBoot打包机制

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

2c77053ba9fb4ebef732a081416c1dda.png

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

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

e973bf68d4fccbc53d24b3e7257b3389.png

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

0b7c6d18017e7309876906e4d74a4986.png

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

SpringBoot应用的启动

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

6df67e4c646566866ad5c591c4d63955.png

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

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

7a7de14505e08c7f29d4c9b63cf0c5ef.png

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

a2d20aafa81d104deb873b3ef72fe2cf.png

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

17ad093897d41e248b0b878bccbee9fd.png

b05f95620491059b1251b5120f165f84.png

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

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

119f71103a77f464095641e826e61fc0.png

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

8454bead573c3814e8ce049c324f7abc.png

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

8e259a8db4bbbd842bedae693c27d971.png

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

SpringBoot应用初始化

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

a7061af8d13cc428cb8b0562d6df6c60.png

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

2efcb0a2b179f8ecaeff35f4c420d612.png

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

929bfc7494a7ac054039f16b79576d33.png

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

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

b8a5b6dceb52a8ad2c6c3e1384c53864.png

前面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类的构造器:

33cda21c87f120b282d9208ce425d0d0.png

在getSpringFactoriesInstances方法中,使用了SpringFactoriesLoader:

d46189021e6832700e5c7b760a8a5123.png

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

bcc128571036eb4f221e9eda43de689b.png

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

83dec6ad003ae81952832467e7203c9c.png

AutoConfiguration

回到@SpringBootApplication注解的定义:

41b344ced7acd6935af33964f6ae7cd5.png

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

87f86f655d82ba97232f83bbfd0340b7.png

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

e1cef2ca870c3a32d6dbda62b28bcb7c.png

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

77ca243fb8aef5ac5f5ccfbac0a5c069.png

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

d435aefd328e77b528a19070b1d036a0.png

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

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

bd09df209e4d4ac502c4dee81ef8bf05.png

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

9fb24234eb1c1abb4f5f1ae000aa0c75.png

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值