浅析 SpringBoot FatJar 机制的设计与实现( 二 )


四、 自定义类加载器的运行机制通常自定义类加载器完成资源加载的核心逻辑为:

  1. 指定资源
  2. 指定委托关系
  3. 指定线程上下文类加载器
  4. 调用逻辑入口方法
所以 SpringBoot FatJar 中自定义 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 的时候作为参数传入
@Overrideprotected List<Archive> getClassPathArchives() throws Exception { List<Archive> 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);}4.2 创建自定义 ClassLoaderprotected void launch(String[] args) throws Exception { JarFile.registerUrlProtocolHandler();//创建类加载器, 并指定归档文件 ClassLoader classLoader = createClassLoader(getClassPathArchives()); launch(args, getMainClass(), classLoader);}//创建类加载器, 将归档文件转换为URLprotected 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]));}//父加载器是AppClassLoaderprotected ClassLoader createClassLoader(URL[] urls) throws Exception {//getClass().getClassLoader() 是系统类加载器,因为默认情况下main方法所在类是由SystemClassLoader加载的,默认情况下是AppClassLoader. return new LaunchedURLClassLoader(urls, getClass().getClassLoader());}4.3 设置线程上下文类加载器,调用程序中的 main 方法public 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();本文转载自微信公众号「架构染色」,可以通过以下二维码关注 。转载本文请联系【架构染色】公众号作者 。




推荐阅读