范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

从原理和源码梳理SpringbootFatJar的机制

  一、概述
  SpringBoot FatJar 的设计,打破了标准 jar 的结构,在 jar 包内携带了其所依赖的 jar 包,通过 jar 中的 main 方法创建自己的类加载器,来识别加载运行其不规范的目录下的代码和依赖。二、标准的 jar 包结构
  打开 Java 的 Jar 文件我们经常可以看到文件中包含着一个META-INF目录,这个目录下会有一些文件,其中必有一个MANIFEST.MF,这个文件描述了该 Jar 文件的很多信息 其中 Main-Class 定义 Jar 文件的入口类,该类必须是一个可执行的类,一旦定义了该属性即可通过 java -jar xxx.jar 来运行该 jar 文件。
  在生产环境是使用 java -jar xxx.jar 的方式来运行 SpringBoot 程序。 这种情况下,SpringBoot 应用真实的启动类并不是我们所定义的带有 main 方法的类,而是 JarLauncher 类。查看 SpringBoot 所打成的 FatJar,其 Main-Class 是org.springframework.boot.loader.JarLauncher,这便是微妙之处。Spring-Boot-Version: 2.1.3.RELEASE Main-Class: org.springframework.boot.loader.JarLauncher Start-Class: com.rock.springbootlearn.SpringbootLearnApplication Spring-Boot-Classes: BOOT-INF/classes/ Spring-Boot-Lib: BOOT-INF/lib/ Build-Jdk: 1.8.0_131 复制代码
  JAR 包中的 MANIFEST.MF 文件详解以及编写规范三、探索JarLauncher
  org.springframework.boot.loader.JarLauncher这个类是哪里来的呢?答案在 spring-boot-loader-***.jar 包中,可找到这个 JarLauncher 类的源码。在项目中加入 maven 依赖,以便查看源码和远程调试。     org.springframework.boot     spring-boot-loader  复制代码
  认真比较可以看出,这个 spring-boot-loader 包中的内容与 SpringBoot 的 FatJar 包中的一部分内容几乎一样。JarLauncher 在 jar 中的位置如下:
  3.1 只能拷贝出来一份儿
  重点重点重点:因 jar 规范要求 Main-Class 所指定的类必须位于 jar 包的顶层目录下,即 org.springframework.boot.loader.JarLauncher 这个 org 必须位于 jar 包中的第一级目录,不能放置在其他的目录下。所以所以所以只能将 spring-boot-loader 这个 jar 包的内容拷贝出来,而不是整个 jar 直接放置于执行 Jar 中。3.2 携带程序所依赖的jar而非仅class
  上边 JarLauncher 的这个 org.springframework.xx 以及 META-INF 这两个目录是符合 jar 包规范的。但是 BOOT-INF 这个目录里边有点像我们开发中的一些用法:依赖 jar 包在 lib 目录下 但按照 jar 包规范 jar 中不能有 jar 包的情况下程序.class 文件在 classes 目录下 但xxx.class 文件应该按照 org.springframework.xx 这样放置在 jar 中的根目录中
  所以classes 和 lib 你也能意识到,这个设计是独特的。早期 jar 包内携带依赖是采用如 maven-shade-plugin 的做法,把依赖的class文件拷贝到目标 jar 中,但也会造成重名(全限定名)的类会出现覆盖的情况。后来 SpringBoot 为了避免覆盖的情况,修改了打包机制,放弃了maven-shade-plugin那种拷贝class的方式,调整为依赖原始 jar 包;这同时意味着改变了 Jar 标准的运行机制,那么要想让classes和lib中代码能够正常运行,你试想一下如果没有自定义的 classLoader 来加载这些类文件,可以嘛?四、 自定义类加载器的运行机制
  自定义类加载器的常规处理:指定资源指定委托关系指定线程上下文类加载器调用逻辑入口方法4.1 指定资源
  构造方法中基于 jar 包的文件系统信息,构造 Archive 对象public ExecutableArchiveLauncher() { 	this.archive = createArchive(); }  protected final Archive createArchive() throws Exception { 	ProtectionDomain protectionDomain = getClass().getProtectionDomain(); 	CodeSource codeSource = protectionDomain.getCodeSource(); 	URI location = (codeSource != null) ? codeSource.getLocation().toURI() : null; 	String path = (location != null) ? location.getSchemeSpecificPart() : null; 	if (path == null) { 		throw new IllegalStateException("Unable to determine code source archive"); 	} 	File root = new File(path); 	if (!root.exists()) { 		throw new IllegalStateException( 				"Unable to determine code source archive from " + root); 	} 	return (root.isDirectory() ? new ExplodedArchive(root) 			: new JarFileArchive(root)); } 复制代码
  采集 jar 包中的 classes 和 lib 目录下的归档文件。后边创建 ClassLoader 的时候作为参数传入@Override protected List getClassPathArchives() throws Exception { 	List archives = new ArrayList<>( 			this.archive.getNestedArchives(this::isNestedArchive)); 	postProcessClassPathArchives(archives); 	return archives; }  protected boolean isNestedArchive(Archive.Entry entry) { 	if (entry.isDirectory()) { 		return entry.getName().equals(BOOT_INF_CLASSES); 	} 	return entry.getName().startsWith(BOOT_INF_LIB); } 复制代码public static void main(String[] args) throws Exception { 	new JarLauncher().launch(args); } 复制代码4.2 创建自定义 ClassLoaderprotected void launch(String[] args) throws Exception { 	JarFile.registerUrlProtocolHandler();         //创建类加载器, 并指定归档文件 	ClassLoader classLoader = createClassLoader(getClassPathArchives()); 	launch(args, getMainClass(), classLoader); } //创建类加载器, 将归档文件转换为URL protected ClassLoader createClassLoader(List archives) throws Exception { 	List urls = new ArrayList<>(archives.size()); 	for (Archive archive : archives) { 		urls.add(archive.getUrl()); 	} 	return createClassLoader(urls.toArray(new URL[0])); } //父加载器是AppClassLoader protected ClassLoader createClassLoader(URL[] urls) throws Exception {         //getClass().getClassLoader() 是系统类加载器,因为默认情况下main方法所在类是由SystemClassLoader加载的,默认情况下是AppClassLoader. 	return new LaunchedURLClassLoader(urls, getClass().getClassLoader()); }  复制代码4.3 设置线程上下文类加载器,调用程序中的 main classpublic static void main(String[] args) throws Exception { 	new JarLauncher().launch(args); } protected void launch(String[] args, String mainClass, ClassLoader classLoader) 		throws Exception {         //设置线程上下文类加载器 	Thread.currentThread().setContextClassLoader(classLoader); 	//调用MANIFEST.MF 中配置的Start-Class: xxx的main方法,还带入了参数         createMainMethodRunner(mainClass, args, classLoader).run(); } 复制代码

从340万个项目中脱颖而出!山东这个高校项目获大学生创新创业大赛铜奖大众网海报新闻记者孙杰济南报道近日,中国国际互联网大学生创新创业大赛组委会公布关于公示第八届中国国际互联网大学生创新创业大赛总决赛有关赛事获奖名单的通知。其中,泰山学院的承泰富农农天猫超市华南中心仓启用!广州70地区包裹当日达CNMO新闻在国内,一般网购商品后23天内会送达,也有电商平台推出了次日达服务,这大大提高了大家的网购便利性。而在此之上,当日达的服务也已经在一些地区展开。据CNMO了解,天猫超市MySQL入坑指南及常见的SQL坑,涨知识了关注互联网技术学堂,获取互联网最新资讯,获取面试干货,走向高薪!MySQL入坑背景MySQL是一种常见的关系型数据库管理系统,被广泛应用于各种应用程序和网站的开发中。然而,由于My共建共享共治嘀嗒出行创新推动顺风车行业规范可持续发展作为移动出行细分领域,顺风车行业经历近十年发展,成为越来越多人的日常出行选择。同时,顺风车在缓解城市拥堵促进节能环保等方面的积极意义,得到越来越广泛认同。在国家层面鼓励发展平台经济卫星通信时代来了?从MWC能看到哪些手机发展方向MWC2023已经落下帷幕,比起过去三年的冷淡,回归线下的MWC显得特别热闹,而一众参展商也是使出浑身解数,带来了一大批前沿技术新产品等。荣耀一加等国产厂商也选择在MWC上发布自己Filecoin价格分析FIL涨至7美元,看涨前景TLDR故障。Filecoin价格今天上涨了10。看涨可能会将FIL带到10美元的阻力位。支撑位于6美元大关Filecoin价格分析显示了开始看涨运行的前景,因为价格在过去24小时巨星科技品类持续拓展,电商丰富渠道,工具龙头优势凸显(报告出品方作者长江证券,赵智勇,倪蕤,曹小敏)源自杭州,手工具走向世界历经四个发展阶段,进入多元化增长时期巨星科技至今为止的发展阶段可分为四个阶段。起步阶段(19931996)1高质量开新局丨湛江经济技术开发区世界500强集聚千亿集群崛起三大投资超百亿美元级巨无霸齐头并进,重大产业集群优势凸显,世界500强企业纷纷抢滩,制造业的骨骼愈加强健,工业经济蓬勃发展的大气候逐步形成早春的东海岛生机勃发,湛江工业主引擎经开区CEIS2022消防技术创新十大品牌评选结果已出,拓普索尔实力入选2023年2月28日,由中国安全产业协会中国消防协会中国安全防范产品行业协会指导,中国安全产业协会应急创新分会应急救援产业网主办及相关行业协会支持的CEIS2022第四届中国应急安加盟商心声投资不是小事,加盟也不是一头热咖啡赛道正在成为实体投资的首选。总第3426期餐企老板内参张心笛文焦虑与运筹帷幄说心里话,第一次开店,怎么可能不担心?从选址筹备就开始愁,到正式为了开业做准备就更愁了。我们开了一家引领非急救转运服务行业高质量发展全国首个非急救转运服务规范团体标准在沪发布3月1日,全国首个非急救转运服务规范团体标准发布会在上海举行。该标准由上海现代服务业联合会上海现代服务业标准创新发展中心与上海聆邻健康科技有限公司上海现代服务业联合会医疗服务专业委
青未了杨柳青青杨柳青青文周政春风一来,冬景还在,残雪如鸡毛,落下狼藉。晨阳下,桃花露红,柳青依依,湖波涟漪。春来了,杨花难以自抑心跳,见了柳青,这心跳愈烈。杨花是在病房认识柳青的。杨花是护士,那热热乎乎炖一锅,鲜到连汤都喝光了冬天,就喜欢吃一些有汤有水的菜,吃完热热乎乎的和大家分享一道砂锅丸子粉丝煲的做法,很适合这个季节的一道菜。这道菜用到的食材很简单,一小碗肉馅,一把粉丝就可以做一小砂锅。做好后,连锅咳嗽最怕这汤,成本不到5毛钱,每天喝两次,润肺止咳又化痰大家好,我是真心爱厨房。今天又来给大家分享美食做法,每一道菜都是用心去研究,详细到每一个步骤,全部是由小编通过实践亲自摸索出来的。为了让大家更好的掌握美食技巧做法,保证您一看就会,打豆浆,切忌黄豆泡好直接打,还需多做2步,细腻丝滑,无豆腥味打豆浆,切忌黄豆泡好直接打,还需多做2步,细腻丝滑,无豆腥味豆浆,是我们家早餐爱喝的饮品,自己在家打豆浆,每个人都喝一碗,总比去外面买各种饮料强。不说每天都喝,至少一周5次是有了,鹿晗关晓彤定居日本?穿情侣装散步太幸福,女方戴钻戒疑好事将近鹿晗关晓彤定居日本?穿情侣装散步太幸福,女方戴钻戒疑好事将近2月2日,据娱乐媒体报道,鹿晗与关晓彤再次现身日本被网友偶遇,两人穿情侣装街头散步看起来感情稳定,引来不少网友围观热议。都是些什么样的人,甘愿受辱也要去日本韩国扫货?温馨提示在阅读此文之前,麻烦您点击一下关注,既方便您进行讨论和分享,又能给您带来不一样的参与感,感谢您的支持!都是些什么样的人,甘愿受辱也要去日本韩国旅游扫货?去给你们主子送钱!中熊孩子到底能有多调皮,妈妈直呼想去icu,满屋子全是泡沫熊孩子怎么淘气?扎爆气球?玩弄大米?nonono,懒人沙发里的泡沫会给你下一场雪熊孩子千千万,折腾人来一套又一套,妈妈边说还小还小,长大了就好,手上已经打电话给120预订icu病房中国恢复日本人签证审批日本只有好好表现听中国话这一个选择中国驻日本大使馆今天下午(129)宣布,恢复对日本公民的签证签发服务。自本月10日起,中国政府暂停向日本公民从日本赴华旅游签发签证,作为对日本政府对中国采取的边境措施的反制措施。针张本智和第一!日本更新奥运积分榜,伊藤美诚石川佳纯情况不妙北京时间1月29日,2023年日本乒乓球全国锦标赛落下帷幕。由于该赛事与日本队内的奥运选拔挂钩,所以打完后各运动员的奥运积分就发生了变化,其中女单登顶的早田希娜依旧稳居榜首,而男单别只是在眼周按摩打圈了,眼霜这样涂,让你的贵妇眼霜不白用!眼霜是一种特殊的护肤品,专门用来滋润和保护眼周肌肤。眼霜具有以下重要性保湿眼霜含有大量的保湿成分,能够有效地补充眼周肌肤所需的水分,避免干燥和细纹。滋养眼霜中常含有维生素矿物质抗氧为什么全家人都喜欢看你好,星期六你好星期六湖南卫视你好,星期六这档正能量的综艺节目,随着时间的延长,如今已经成为我们全家人的必看选择。笔者是新闻媒体的特约记者,综艺节目也是我关注的范围,而家人则是久看成了专家。对