浅析Spring Boot中的spring-boot-load模块

一、前言

正常情况下classloader只能找到jar里面当前目录或者文件类里面的*.class文件。为了能够加载嵌套jar里面的资源之前都是把嵌套jar里面的class文件和应用的class文件打包为一个jar,这样就不存在嵌套jar了,但是这样做就不能很清晰的知道应用到底依赖了哪些东西,哪些是应用自己的,另外多个jar里面的class可能内容不一样但是文件名却一样。springboot中spring-boot-loader就是为优雅解决这个问题而诞生的。

spring-boot-loader模块允许我们使用java -jar archive.jar运行包含嵌套依赖jar的jar或者war文件,它提供了三种类启动器 (JarLauncher, WarLauncher and PropertiesLauncher),这些类启动器的目的一样都是为了能够加载嵌套在jar里面的资源(比如class文件,配置文件等)。[Jar|War]Launcher固定去查找当前jar的lib目录里面的嵌套jar文件里面的资源。

二、spring-boot-loader模块提供的jar目录结构

Springboot中jar文件格式固定如下:

archive.jar
 |
 +-META-INF(1)
 | +-MANIFEST.MF
 +-org(2)
 | +-springframework
 | +-boot
 | +-loader
 |  +-<spring boot loader classes>
 +-com(3)
 | +-mycompany
 | + project
 | +-YouClasses.class
 +-lib(4)
 +-dependency1.jar
 +-dependency2.jar
  • 结构(1)jar文件中MANIFEST.MF文件存放处
  • 结构(2) Spring-boot-loader本身需要的class放置处
  • 结构(3) 应用本身的文件放置处
  • 结构(4)应用依赖的jar固定放到lib目录。

那么spring-boot是如何去按照这个结构加载资源那?

  • 首先在打包时候会使用spring-boot-maven-plugin插件重写打成的jar文件,会设置META-INF/MANIFEST.MF中的
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: com.mycompany.project.MyApplication

并拷贝spring-boot-loader包里面的class文件到结构(2),应用依赖拷贝到(4)应用类拷贝到(3)

  • 通过java -jar archive.jar 运行时候Launcher会去加载JarLauncher类并执行其中的main函数,JarLauncher主要关心构造一个合适的URLClassLoader加载器用来调用我们应用程序(MyApplication)的main方法。

三、spring-boot-maven-plugin插件打包流程分析

注:这里需要思考下为何要拷贝本来应该放入到lib里面的spring-boot-loader.jar里面的class到结构(2)?

四、JarLauncher执行流程分析

看完这个流程在分析下第三节留的问题,如流程图首先使用Appclassloader加载了JarLauncher类并创建了LaunchedURLClassLoader类,而LaunchedURLClassLoader是属于spring-boot-loader.jar包里面的,而Appclassloader是普通的加载器不能加载嵌套的jar里面的文件,所以如果把spring-boot-loader.jar放到lib 目录下,Appclassloader将找不到LaunchedURLClassLoader。所以在打包时候

拷贝本来应该放入到lib里面的spring-boot-loader.jar里面的class到结构(2)。

五、总结

spring-boot-load模块通过自定义jar包结构自定义类加载器优雅的实现了嵌套jar资源的加载,通过打包时候重新设置启动类和组织jar结构,通过运行时设置自定义加载器来实现嵌套jar资源加载。

您可能感兴趣的文章:

  • 详解Spring Boot 自定义PropertySourceLoader
  • 深入浅析Spring-boot-starter常用依赖模块
  • SpringBoot 监控管理模块actuator没有权限的问题解决方法
  • SpringBoot创建maven多模块项目实战代码
  • 详解Maven 搭建spring boot多模块项目(附源码)
  • 浅谈springboot多模块(modules)开发
时间: 2018-01-25

详解Spring Boot 自定义PropertySourceLoader

SpringBoot 的配置文件内置支持 properties.xml.yml.yaml 几种格式,其中 properties和xml 对应的Loader类为 PropertiesPropertySourceLoader ,yml和yaml 对应的Loader类为 YamlPropertySourceLoader. 观察这2个类可以发现,都实现自接口 PropertySourceLoader .所以我们要新增支持别的格式的配置文件,就可以通过实现接口 PropertySourceLoader 来

SpringBoot创建maven多模块项目实战代码

工作中一直都是一个人奋战一人一个项目,使用maven管理,看这个也挺好,但是总感觉没有充分发挥maven的功能,于是研究了一下这个,网上关于这个的文章很多,虽然不是很好,但我从中收获了很多,在这集百家所长,写一份实战记录,大家跟着我一块做吧! 声明:构建多模块不是最难的,难点是如果把多模块打包成一个执行jar. SpringBoot官方推崇的是富jar,也就是jar文件启动项目,所以如果在这里打war包我不具体介绍,如果需要的朋友可以给我留言,我回复. 建议clone项目后,在看教程(有不足的地

详解Maven 搭建spring boot多模块项目(附源码)

本文介绍了Maven 搭建spring boot多模块项目,分享给大家,具体如下: 备注:所有项目都在idea中创建 1.idea创建maven项目 1-1: 删除src,target目录,只保留pom.xml 1-2: 根目录pom.xml可被子模块继承,因此项目只是demo,未考虑太多性能问题,所以将诸多依赖.都写在根级`pom.xml`,子模块只需继承就可以使用. 1-3: 根级pom.xml文件在附录1 1-4: 依赖模块 mybatis spring-boot相关模块 2.创建子模块(

深入浅析Spring-boot-starter常用依赖模块

Spring-boot的2大优点: 1.基于Spring框架的"约定优先于配置(COC)"理念以及最佳实践之路. 2.针对日常企业应用研发各种场景的Spring-boot-starter自动配置依赖模块,且"开箱即用"(约定spring-boot-starter- 作为命名前缀,都位于org.springframenwork.boot包或者命名空间下). 应用日志和spring-boot-starter-logging 常见的日志系统大致有:java.util默认提

SpringBoot 监控管理模块actuator没有权限的问题解决方法

SpringBoot 1.5.9 版本加入actuator依赖后,访问/beans 等敏感的信息时候报错,如下 Tue Mar 07 21:18:57 GMT+08:00 2017 There was an unexpected error (type=Unauthorized, status=401). Full authentication is required to access this resource. 肯定是权限问题了.有两种方式: 1.关闭权限:application.prop

浅谈springboot多模块(modules)开发

为何模块开发 先举个栗子,同一张数据表,可能要在多个项目中或功能中使用,所以就有可能在每个模块都要搞一个mybatis去配置.如果一开始规定说这张表一定不可以改字段属性,那么没毛病.但是事实上, 一张表从项目开始到结束,不知道被改了多少遍,所以,你有可能在多个项目中去改mybatis改到吐血! 在举一个栗子,一个web服务里包含了多个功能模块,比如其中一个功能可能会消耗大量资源和时间,当用户调用这个功能的时候,可能会影响到其他功能的正常使用,这个时候,如果把各个功能模块分出来单独部署,然后通过h

浅谈springboot项目中定时任务如何优雅退出

在一个springboot项目中需要跑定时任务处理批数据时,突然有个Kill命令或者一个Ctrl+C的命令,此时我们需要当批数据处理完毕后才允许定时任务关闭,也就是当定时任务结束时才允许Kill命令生效. 启动类 启动类上我们获取到相应的上下文,捕捉相应命令.在这里插入代码片 @SpringBootApplication /**指定mapper对应包的路径*/ @MapperScan("com.youlanw.kz.dao") /**开启计划任务*/ @EnableScheduling

浅谈springboot内置tomcat和外部独立部署tomcat的区别

前两天,我去面了个试,面试官问了我个问题,独立部署的tomcat跟springboot内置的tomcat有什么区别,为什么存在要禁掉springboot的tomcat然后将项目部署到独立的tomcat当中? 我就想,不都一个样?独立部署的tomcat可以配置优化?禁AJP,开多线程,开nio?而且springboot内置的tomcat多方便,部署上服务器写个java脚本运行即可.现在考虑下有什么条件能优于内置tomcat的. 1.tomcat的优化配置多线程?内置的也可以配置多线程 server

浅谈原型对象的常用开发模式

1.构造函数和原型组合使用模式:原型对象虽然可以对所有实例的属性和方法共享,但是也有它的局限性,正是因为可以共享,也导致某一个实例对象若改变了共享的属性和方法,其他对象在使用时会收到影响. 所以可以组合使用构造函数式和原型模式,在实际开发中这种模式也应用的最为广泛. 2.动态原型模式:就是把属性和方法都封装到构造函数中 例如: function Person(name,age,sex){ this.name=name; this.age=age; this.sex=sex; if(typeof

浅谈springboot 属性定义

本文介绍了浅谈springboot 属性定义,分享给大家.具体如下: 简单属性自定义 一般属性可以定义在通用的配置文件application.properties里面 # 自定义属性 boot.userName = yuxi 如何获取呢? 按照spring的获取方式就可以了,很简单 @Value(value = "${boot.userName}") private String userName; 复杂属性自定义 在配置里配置属性 # 复杂属性 test.id=1 test.name

浅谈SpringBoot处理url中的参数的注解

1.介绍几种如何处理url中的参数的注解 @PathVaribale 获取url中的数据 @RequestParam 获取请求参数的值 @GetMapping 组合注解,是 @RequestMapping(method = RequestMethod.GET) 的缩写 (1)PathVaribale 获取url中的数据 看一个例子,如果我们需要获取Url=localhost:8080/hello/id中的id值,实现代码如下: @RestController public class Hello

浅谈python 导入模块和解决文件句柄找不到问题

如果你退出 Python 解释器并重新进入,你做的任何定义(变量和方法)都会丢失.因此,如果你想要编写一些更大的程序,为准备解释器输入使用一个文本编辑器会更好,并以那个文件替代作为输入执行.这就是传说中的脚本 Python 提供了一个方法可以从文件中获取定义,在脚本或者解释器的一个交互式实例中使用.这样的文件被称为模块. 导入模块: python导入模块默认是从sys.path的路径中查找.所以应该把这个模块放在sys.path的值对应的文件夹里.否则就找不到要导入的模块.如果在cmd中或者ID

浅谈spring-boot的单元测试中,@Before不被执行的原因

我们先来看下笔者的单元测试的依赖版本: <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.6.RELEASE</version> <relativePath/> <!-- lookup parent from reposi

浅谈SpringBoot主流读取配置文件三种方式

读取配置SpringBoot配置文件三种方式 一.利用Bean注解中的Value(${})注解 @Data @Component public class ApplicationProperty { @Value("${application.name}") private String name; } 该方式可以自动读取当前配置文件appliation.yml  或者application.properties中的配置值 区别在于读取yml文件时候支持中文编码,peoperties需

浅谈springboot中tk.mapper代码生成器的用法说明

问:什么是tk.mapper? 答:这是一个通用的mapper框架,相当于把mybatis的常用数据库操作方法封装了一下,它实现了jpa的规范,简单的查询更新和插入操作都可以直接使用其自带的方法,无需写额外的代码. 而且它还有根据实体的不为空的字段插入和更新的方法,这个是非常好用的哈. 而且它的集成非常简单和方便,下面我来演示下使用它怎么自动生成代码. pom中引入依赖,这里引入tk.mybatis.mapper的版本依赖是因为在mapper-spring-boot-starter的新版本中没有