spring boot 包结构
Nested JARs
Java没有提供任何标准的方法来加载嵌套的jar文件(即本身包含在jar中的jar文件)。如果需要分发自包含的应用程序,而该应用程序可以从命令行运行而无需解压缩,则这可能会有问题。
为了解决这个问题,许多开发人员使用“阴影”jar。一个阴影jar将所有类从所有jar打包成一个“uber jar”。这些jar的问题是,很难看到应用程序中实际存在哪些库,如果在多个jar中使用相同的文件名(但内容不同),也会有问题。
Spring Boot采用了一种不同的方法,允许您直接嵌套jar。
The Executable Jar File Structure
与Spring Boot Loader兼容的jar文件的结构应如下所示:
example.jar
|
+-META-INF
| +-MANIFEST.MF
+-org
| +-springframework
| +-boot
| +-loader
| +-<spring boot loader classes>
+-BOOT-INF
+-classes
| +-mycompany
| +-project
| +-YourClasses.class
+-lib
+-dependency1.jar
+-dependency2.jar
应用程序类应该放在嵌套的BOOT-INF/classes目录中。依赖项应该放在嵌套的BOOT-INF/lib目录中。
The Executable War File Structure
与Spring Boot Loader兼容的war文件的结构应如下:
example.war
|
+-META-INF
| +-MANIFEST.MF
+-org
| +-springframework
| +-boot
| +-loader
| +-<spring boot loader classes>
+-WEB-INF
+-classes
| +-com
| +-mycompany
| +-project
| +-YourClasses.class
+-lib
| +-dependency1.jar
| +-dependency2.jar
+-lib-provided
+-servlet-api.jar
+-dependency3.jar
依赖项应该放在嵌套的WEB-INF/lib目录中。运行嵌入式时需要但部署到传统web容器时不需要的任何依赖项都应该放在WEB-INF/lib-provided中。
Spring Boot’s “JarFile” Class
用于支持加载嵌套jar的核心类是org.springframework.boot.loader.jar.JarFile。它允许您从标准jar文件或嵌套的子jar数据加载jar内容。第一次加载时,每个JarEntry的位置都映射到外部jar的物理文件偏移量,如下例所示:
myapp.jar
+-------------------+-------------------------+
| /BOOT-INF/classes | /BOOT-INF/lib/mylib.jar |
|+-----------------+||+-----------+----------+|
|| A.class ||| B.class | C.class ||
|+-----------------+||+-----------+----------+|
+-------------------+-------------------------+
^ ^ ^
0063 3452 3980
前面的示例显示了如何在位于0063位置的myapp.jar中的/BOOT-INF/classes中找到A.class。嵌套jar中的B.class实际上可以在位置3452的myapp.jar中找到,而C.class位于位置3980。
有了这些信息,我们可以通过寻找外部jar的适当部分来加载特定的嵌套条目。我们不需要解压缩存档文件,也不需要将所有条目数据读入内存。
Compatibility with the Standard Java “JarFile”
Spring引导加载程序试图保持与现有代码和库的兼容性。org.springframework.boot.loader.jar.JarFile 从java.util.jar.JarFile 扩展而来,应该作为一个替换项。getURL()方法返回一个URL,该URL打开与java.net.JarURLConnection兼容的连接,并可与java的URLClassLoader一起使用。
Launching Executable Jars
boot.loader.Launcher类是一个特殊的引导类,用作可执行jar的主要入口点。它是jar文件中的实际主类,用于设置适当的URLClassLoader并最终调用你的main()方法。
有三个子类(JarLauncher、WarLauncher和PropertiesLauncher)。它们的目的是从目录中的嵌套jar文件或war文件(而不是明确的类路径上)加载资源(.class文件等)。对于JarLauncher和WarLauncher嵌套路径是固定的。JarLauncher looks in BOOT-INF/lib/, and WarLauncher looks in WEB-INF/lib/and WEB-INF/lib-provided/.如果需要更多,可以在这些位置添加额外的jar。默认情况下,PropertiesLauncher在应用程序归档文件的BOOT-INF/lib/中查找。您可以通过在loader.properties中设置名为LOADER_PATH或LOADER.PATH的环境变量(这是以逗号分隔的存档中的目录、存档或目录列表)来添加其他位置。
Launcher Manifest
您需要指定适当的启动程序作为META-INF/MANIFEST.MF的主类属性。要启动的实际类(即包含main方法的类)应在Start-class属性中指定。
以下示例显示可执行jar文件的典型MANIFEST.MF:
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: com.mycompany.project.MyApplication
对于war文件,如下所示:
Main-Class: org.springframework.boot.loader.WarLauncher
Start-Class: com.mycompany.project.MyApplication
不需要在清单文件中指定类路径项。类路径是从嵌套的jar中推导出来的。
PropertiesLauncher Features
PropertiesLauncher有一些特殊功能,可以使用外部属性(系统属性、环境变量、清单条目或loader.properties)启用。下表描述了这些属性:
loader.path |
Comma-separated Classpath, such as lib,${HOME}/app/lib. Earlier entries take precedence, like a regular -classpath on the javac command line. |
loader.home |
Used to resolve relative paths in loader.path. For example, given loader.path=lib, then ${loader.home}/lib is a classpath location (along with all jar files in that directory). This property is also used to locate a loader.properties file, as in the following example /opt/app It defaults to ${user.dir}. |
loader.args |
Default arguments for the main method (space separated). |
loader.main |
Name of main class to launch (for example, com.app.Application). |
loader.config.name |
Name of properties file (for example, launcher). It defaults to loader. |
loader.config.location |
Path to properties file (for example, classpath:loader.properties). It defaults to loader.properties. |
loader.system |
Boolean flag to indicate that all properties should be added to System properties. It defaults to false. |
当指定为环境变量或清单项时,应使用以下名称:
key |
Manifest entry |
Environment variable |
loader.path |
Loader-Path |
LOADER_PATH |
loader.home |
Loader-Home |
LOADER_HOME |
loader.args |
Loader-Args |
LOADER_ARGS |
loader.main |
Start-Class |
LOADER_MAIN |
loader.config.location |
Loader-Config-Location |
LOADER_CONFIG_LOCATION |
loader.system |
Loader-System |
LOADER_SYSTEM |
构建插件会在构建胖jar时自动将主类属性移动到Start Class。如果使用该属性,请使用Main class属性指定要启动的类的名称。
以下规则适用于使用PropertiesLauncher:
loader.properties:
在loader.home中搜索,然后在类路径的根目录中classpath搜索,然后在类路径中搜索/BOOT-INF/classes。使用具有该名称的文件的第一个位置。
loader.home:
仅当未指定loader.config.location时,它才是附加属性文件(覆盖默认值)的目录位置。
loader.path:
可以包含目录(递归扫描jar和zip文件)、存档路径、存档中扫描jar文件的目录(例如dependencies.jar!)!/或通配符模式(用于默认的JVM行为)。存档路径可以相对于loader.home或文件系统中带有jar:file:prefix的任何位置。
loader.path:
(如果为空)默认为BOOT-INF/lib(如果从存档运行,则表示本地目录或嵌套目录)。因此,当没有提供额外的配置时,PropertiesLauncher的行为与JarLauncher相同。
loader.path:
无法用于配置loader.properties的位置(启动PropertiesLauncher时用于搜索后者的类路径是JVM类路径)。
占位符替换是在使用前从系统和环境变量以及所有值上的属性文件本身完成的。
属性properties 的搜索顺序(在多个地方查找是有意义的)是环境变量、系统属性、loader.properties、分解的存档清单和存档清单。
Executable Jar Restrictions
在使用Spring Boot Loader打包应用程序时,需要考虑以下限制:
压缩:必须使用ZipEntry.STORED方法保存嵌套JAR的ZipEntry。这是必需的,这样我们就可以直接查找嵌套JAR中的单个内容。嵌套JAR文件本身的内容仍然可以压缩,外部JAR中的任何其他条目也可以压缩。
SystemclassLoader:启动的应用程序在加载类时应该使用Thread.getContextClassLoader()(默认情况下大多数库和框架都这样做)。试图用ClassLoader.getSystemClassLoader()加载嵌套的JAR类失败。 java.util.Logging 总是使用系统类加载器。因此,您应该考虑使用不同的日志记录实现。