java -jar启动springboot项目,spring boot linux jar包启动

  java -jar启动springboot项目,spring boot linux jar包启动

  一.导言二jar包III的内部结构。加载过程1。一些班级使用了2。过程分析四。摘要

  00-1010用过SprongBoot,玩过jar包的人都应该知道,目标文件一般生成两个文件,一个是带的包。另一个是。jar .原始文件。然后用SpringBoot会打出来两个包,作用是什么。jar .原创?而java -jar是如何启动SpringBoot项目的,做了哪些操作?

  其实,jar.original是SpringBoot重新打包之前maven的原始jar包。它只包含项目的用户类,不包含其他依赖的jar包。生成之后,SpringBoot重新打包,并最终生成。jar包,它包含原始jar包和其他引用依赖项。下面说的罐子包都是跳趾二次加工做的包。

  00-1010 Spring Boot打出来的jar包可以直接解压查看内部结构。一般有三个目录。

  BOOT-INF:这个文件夹下有两个folders类用来存储用户类,也就是原来jar.original中的类;还有lib,它是这个原始jar.original引用的依赖项。META-INF:这里是java -jar启动的门户信息,记录了门户类的位置等信息。Org:Springboot加载程序代码,通过它启动。这里主要介绍一下/BOOT-INF/MANIFEST.MF文件

  Main-class : org . spring framework . boot . loader . jarlauncherstart-class : cn.com . spring boot . center . autheenterbootstrapMain-Class:记录java -jar的启动门户,用这个命令启动时会调用这个门户类的main方法。很明显,Springboot转移的是启动门户,并不是用户编写的xxx.xxx.BootStrap的门户类。

  Start-Class:记录了用户写的xxx.xxx.BootStrap的入口类。嵌入的jar包加载后,LaunchedURLClassLoader线程加载类将用于加载用户编写的入口类。

  

目录

  

一、简介

3.1.1 Archive

  实现迭代器接口的archive接口有两个子类,一个是JarFileArchive对jar包文件的使用,提供返回这个jar文件对应的url或者这个jar文件的MANIFEST文件数据信息等操作。ExplodedArchive是使用文件目录。还有获取这个目录的url的方法,以及获取这个目录下所有存档文件的方法。

  3.1.2 Launcher

  启动程序的基类,最终由JarLauncher#main()启动。ExecutableArchiveLauncher冒烟

  象类,提供了获取Start-Class类路径的方法,以及是否还有内嵌对应文件的判断方法和获取到内嵌对应文件集合的后置处理方法的抽象,由子类JarLauncherWarLauncher自行实现。

  

  3.1.3 Spring.loader下的JarFile和JarEntry

  ​ jarFile继承于jar.util.jar.JarFileJarEntry继承于java.util.jar.JarEntry,对原始的一些方法进行重写覆盖。每一个JarFileArchive都拥有一个JarFile方法,用于存储这个jar包对应的文件,而每一个JarFile都有一个JarFileEntries,JarFileEntries是一个迭代器。总的来说,在解析jar包时,会将jar包内的文件封装成JarEntry对象后由JarFile对象保存文件列表的迭代器。所以JarFileArchiveJarFileEntries之间是通过JarFile连接,二者都可以获取到JarFile对象。

  

  

2.过程分析

MANIFEST.MF文件中的Main-class指向入口开始。

  创建JarLauncher并且通过它的launch()方法开始加载jar包内部信息。

  

public static void main(String[] args) throws Exception { new JarLauncher().launch(args);}
JarLauncher的空构造方法时一个空实现,刚开始看的时候还懵了一下,以为是在后续的操作中去加载的文件,其实不然,在创建时由父类ExecutableArchiveLauncher的构造方法去加载的文件。

  加载为归档文件对象:

  

this.archive = createArchive();
具体的加载方法:判断路径是否是一个文件夹,是则返回ExplodedArchive对象,否则返回JarFileArchive 进入JarFileArchive类:通过这个new方法创建JarFile对象

  

public class JarFileArchive implements Archive { public JarFileArchive(File file, URL url) throws IOException { this(new JarFile(file)); this.url = url; }}
进入到JarFile方法:通过RandomAccessDataFile读取文件的内容,并传递给本类中的方法进行具体的解析。

  

public class JarFile extends java.util.jar.JarFile { public JarFile(File file) throws IOException { this(new RandomAccessDataFile(file)); }}
进入jarLauncherlaunch方法:注册URL协议的处理器,没有指定时,默认指向org.springframework.boot.loader包路径,获取类路径下的归档文件Archive并通过这些归档文件的URL,创建线程上下文类加载器,使用类加载器和用户编写的启动入口类,通过反射调用它的main方法。

  

protected void launch(String[] args) throws Exception { JarFile.registerUrlProtocolHandler(); ClassLoader classLoader = createClassLoader(getClassPathArchives()); launch(args, getMainClass(), classLoader);}
JarLaunchergetClassPathArchives是在ExecutableArchiveLauncher中实现:获取归档文件中满足EntryFilterg过滤器的项,isNestedArchive方法由具体的之类实现。获取到当前归档文件下的所有子归档文件之后的后置操作,是一个扩展点。在JarLauncher中是一个空实现。

  JarLauncher的具体实现,这里通过判断是否在BOOT-INF/lib/包下返回true 也就是说只会把jar包下的BOOT-INF/lib/下的文件加载为Archive对象

  

protected boolean isNestedArchive(Archive.Entry entry) { if (entry.isDirectory()) { return entry.getName().equals(BOOT_INF_CLASSES); } return entry.getName().startsWith(BOOT_INF_LIB);}
JarFileArchivegetNestedArchives方法:若匹配器匹配到则获取内嵌归档文件。

  具体的获取内嵌归档文件逻辑:根据具体的Entry对象,创建JarFile对象并封装成归档文件对象后返回。

  

protected Archive getNestedArchive(Entry entry) throws IOException { try { JarFile jarFile = this.jarFile.getNestedJarFile(jarEntry); return new JarFileArchive(jarFile); }}
获取到参数entry对应的RandomAccessData对象,这里根据springboot扩展的url协议,在父路径的基础上添加!/来标记子包。

  

private JarFile createJarFileFromFileEntry(JarEntry entry) throws IOException { RandomAccessData entryData = this.entries.getEntryData(entry.getName()); return new JarFile(this.rootFile, this.pathFromRoot + "!/" + entry.getName(), entryData, JarFileType.NESTED_JAR);}
到这基本上读取jar内部信息,加载为对应归档文件对象的大概过程已经讲完了,接下来分析一下在获取到了整个jar的归档文件对象后的处理。

  通过归档文件对象列表,获取对应的url信息,并通过url信息创建LaunchedURLClassLoader

  

protected ClassLoader createClassLoader(List<Archive> archives) { List<URL> urls = new ArrayList<URL>(archives.size()); for (Archive archive : archives) { urls.add(archive.getUrl()); } return createClassLoader(urls.toArray(new URL[urls.size()]));}
获取到对应的LaunchedUrlClassLoader类加载器之后,设置线程的上下文类加载器为该加载器。根据MANIFI.MF文件中的start-classs信息创建项目启动入口主类对象,并通过返回对象的run方法启动

  

protected void launch(String[] args, String mainClass, ClassLoader classLoader) { Thread.currentThread().setContextClassLoader(classLoader); createMainMethodRunner(mainClass, args, classLoader).run();}
进入MainMethodRunnerrun方法:先通过当前线程获取到main入口类,然后通过反射调用启动项目启动类的main方法

  

public void run() throws Exception { Class<?> mainClass = Thread.currentThread().getContextClassLoader() .loadClass(this.mainClassName); Method mainMethod = mainClass.getDeclaredMethod("main", String[].class); mainMethod.invoke(null, new Object[] { this.args });}
最后来说一下这个LaunchedURLClassLoader,它继承于URLClassLoader,并重写了loadClass方法

  LaunchedClassLoaderloadClass方法:调用父类loadClass方法,走正常委派流程,最终会被LaunchURLClassLoader加载。

  

@Overrideprotected Class<?> loadClass(String name, boolean resolve){ try { try { definePackageIfNecessary(name); } return super.loadClass(name, resolve); }}
进入URLClassLoader中根据springboot解析进行解析。根据名称将路径转化为以.class结尾的/分隔的格式。通过UrlClassPath对象根据路径获取资源类文件

  

new PrivilegedExceptionAction<Class<?>>() { public Class<?> run() throws ClassNotFoundException { String path = name.replace(., /).concat(".class"); Resource res = ucp.getResource(path, false); if (res != null) { try { return defineClass(name, res); } } } }

  

四、总结

Springboot主要实现了对URL加载方式进行了扩展,并且对一些对象ArchiveJarFileEntry等进行了抽象和扩展,最后使用LaunchedUrlClassLoader来进行处理。

  到此这篇关于SpringBoot的jar包如何启动的实现的文章就介绍到这了,更多相关SpringBoot jar包启动内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: