有关 fat_jar结构与原理
的部分,官方文档描述的比较详细了。因此本文是对官方文档的简单补充。
Launcher
springboot应用的fatjar启动方式
并不是通过应用程序的主类直接启动的,而是通过Launcher代理启动的。
Launcher 有三种子类: JarLauncher、WarLauncher、PropertiesLauncher。
- JarLauncher: 加载
BOOT-INF/lib/
下的类
- WarLauncher: 加载
WEB-INF/lib/
和WEB-INF/lib-provided/
下的类
- PropertiesLauncher: 加载
BOOT-INF/lib/
下的类,同时可以使用 loader.path
添加更多的类扫描路径
下面以JarLauncher为例,简单介绍下springboot的启动过程。
###JarLauncher
JarLauncher 的源码非常简单:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class JarLauncher extends ExecutableArchiveLauncher { static final String BOOT_INF_CLASSES = "BOOT-INF/classes/"; static final String BOOT_INF_LIB = "BOOT-INF/lib/";
public JarLauncher() { }
protected JarLauncher(Archive archive) { super(archive); }
@Override 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); } }
|
Launcher.launch() 源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| public abstract class Launcher {
protected void launch(String[] args) throws Exception { JarFile.registerUrlProtocolHandler(); ClassLoader classLoader = createClassLoader(getClassPathArchives()); launch(args, getMainClass(), classLoader); } protected ClassLoader createClassLoader(List<Archive> archives) throws Exception { List<URL> urls = new ArrayList<>(archives.size()); for (Archive archive : archives) { urls.add(archive.getUrl()); } return createClassLoader(urls.toArray(new URL[0])); } protected ClassLoader createClassLoader(URL[] urls) throws Exception { return new LaunchedURLClassLoader(urls, getClass().getClassLoader()); } protected void launch(String[] args, String mainClass, ClassLoader classLoader) throws Exception { Thread.currentThread().setContextClassLoader(classLoader); createMainMethodRunner(mainClass, args, classLoader).run(); } protected MainMethodRunner createMainMethodRunner(String mainClass, String[] args, ClassLoader classLoader) { return new MainMethodRunner(mainClass, args); } protected abstract String getMainClass() throws Exception;
protected abstract List<Archive> getClassPathArchives() throws Exception; 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)); }
}
|
###PropertiesLauncher
有关PropertiesLauncher 更详细的配置 可以 翻看 官方文档 。
参考
https://docs.spring.io/spring-boot/docs/current/reference/html/executable-jar.html
https://segmentfault.com/a/1190000013532009