springboot可执行jar包
springboot 打出的jar包,在通过java -jar命令启动时,是通过JarLauncher代理启动的。可以自定义ClassLoader,以实现对jar文件内(jar in jar)或其他路径下jar、class或资源文件的加载。
JarLauncher可以加载内部/BOOT-INF/lib下的jar及/BOOT-INF/classes下的应用class。
MAINFEST.MF文件
Manifest-Version: 1.0
Implementation-Title: springboot-demo
Implementation-Version: 0.0.1-SNAPSHOT
Archiver-Version: Plexus Archiver
Built-By: yixiao
Implementation-Vendor-Id: com.baofu.demo
Spring-Boot-Version: 1.5.3.RELEASE
Implementation-Vendor: Pivotal Software, Inc.
Main-Class: org.springframework.boot.loader.JarLauncher //启动类
Start-Class: com.baofu.demo.SpringbootDemoApplication //入口类
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Created-By: Apache Maven 3.2.1
Build-Jdk: 1.8.0_144
Implementation-URL: http://projects.spring.io/spring-boot/springboot-d
emo/
在JarLauncher类的main方法中创建一个新的JarLauncher类并调用父类的launch方法
public class JarLauncher extends ExecutableArchiveLauncher {
public JarLauncher() {}
public static void main(String[] args) throws Exception {
new JarLauncher().launch(args);
}
}
launch方法
protected void launch(String[] args) throws Exception {
// 在系统属性中设置注册了自定义的URL处理器:org.springframework.boot.loader.jar.Handler
JarFile.registerUrlProtocolHandler();
//创建新的类加载器 sun.misc.Launcher$AppClassLoader
ClassLoader classLoader = this.createClassLoader(this.getClassPathArchives());
this.launch(args, this.getMainClass(), classLoader);
}
protected void launch(String[] args, String mainClass, ClassLoader classLoader) throws Exception {
//设置当前线程上下文类加载器
Thread.currentThread().setContextClassLoader(classLoader);
//入口类(Start-Class: com.baofu.demo.SpringbootDemoApplication),创建runer并启动,执行
this.createMainMethodRunner(mainClass, args, classLoader).run();
}
run方法
public void run() throws Exception {
//使用定义好的classLoader加载springboot工程入口类,com.baofu.demo.SpringbootDemoApplication
Class<?> mainClass = Thread.currentThread().getContextClassLoader()
.loadClass(this.mainClassName);
// 反射获取main方法
Method mainMethod = mainClass.getDeclaredMethod("main", String[].class);
// 执行main方法
mainMethod.invoke(null, new Object[] { this.args });
}
main方法
Ark包启动加载过程
ARK包通过java -jar 启动
MANIFEST.MF文件
Manifest-Version: 1.0
Implementation-Title: ark-springboot-dubbo
Implementation-Version: 1.0.0-SNAPSHOT
Archiver-Version: Plexus Archiver
Built-By: lux
Ark-Biz-Name: ark-springboot-dubbo
Sofa-Ark-Version: 0.5.1
Implementation-Vendor-Id: com.lux.sofa.ark.demo
deny-import-packages:
priority: 100
Implementation-Vendor: Pivotal Software, Inc.
Main-Class: com.alipay.sofa.ark.bootstrap.ArkLauncher //启动类
deny-import-classes: com.alipay.sofa.SampleClass1,com.alipay.sofa.Samp
leClass2
Ark-Container-Root: SOFA-ARK/container/
deny-import-resources:
Ark-Biz-Version: 1.0.0-SNAPSHOT
Created-By: Apache Maven 3.5.0
Build-Jdk: 1.8.0_77
Implementation-URL: http://projects.spring.io/spring-boot/ark-springbo
ot-dubbo/
通过java -jar 启动ark包之后,执行的是com.alipay.sofa.ark.bootstrap.ArkLauncher中的main方法
public static void main(String[] args) throws Exception {
//新创建一个ArkLauncher对象并启动
new ArkLauncher().launch(args);
}
launch方法
public void launch(String[] args) throws Exception {
// 在系统属性中设置注册了自定义的URL处理器:com.alipay.sofa.ark.loader
JarFile.registerUrlProtocolHandler();
// 创建classLoader
ClassLoader classLoader = createContainerClassLoader(getContainerArchive());
// 添加命令参数-Ajar=[value]
List<String> attachArgs = new ArrayList<>();
attachArgs
.add(String.format("%s%s=%s", CommandArgument.ARK_CONTAINER_ARGUMENTS_MARK,
CommandArgument.FAT_JAR_ARGUMENT_KEY, getExecutableArchive().getUrl()
.toExternalForm()));
attachArgs.addAll(Arrays.asList(args));
// 执行com.alipay.sofa.ark.container.ArkContainer中的main方法
launch(attachArgs.toArray(new String[attachArgs.size()]), getMainClass(), classLoader);
}
launch方法
protected Object launch(String[] args, String mainClass, ClassLoader classLoader) throws Exception {
// 获取当前线程所在类加载器
ClassLoader old = Thread.currentThread().getContextClassLoader();
try {
// 设置线程上下文类加载器为自定义类加载器
Thread.currentThread().setContextClassLoader(classLoader);
// 创建runner执行com.alipay.sofa.ark.container.ArkContainer中的main方法
return createMainMethodRunner(mainClass, args).run();
} finally {
// 类加载器还原
Thread.currentThread().setContextClassLoader(old);
}
}
run方法
public Object run() throws Exception {
// 加载com.alipay.sofa.ark.bootstrap.ArkLauncher类
Class<?> mainClass = Thread.currentThread().getContextClassLoader()
.loadClass(this.mainClassName);
// 调用com.alipay.sofa.ark.bootstrap.ArkLauncher类中的main方法
Method mainMethod = mainClass.getDeclaredMethod("main", String[].class);
return mainMethod.invoke(null, new Object[] { this.args });
}
com.alipay.sofa.ark.container.ArkContainer中的main方法
public static Object main(String[] args) throws ArkException {
// 参数长度至少为1 -Ajar=....
if (args.length < MINIMUM_ARGS_SIZE) {
throw new ArkException("Please provide suitable arguments to continue !");
}
try {
// 获取arkBiz包路径
LaunchCommand launchCommand = LaunchCommand.parse(args[ARK_COMMAND_ARG_INDEX],
Arrays.copyOfRange(args, MINIMUM_ARGS_SIZE, args.length));
if (launchCommand.isExecutedByCommandLine()) {
// 获取可执行arkBiz包
ExecutableArkBizJar executableArchive = new ExecutableArkBizJar(new JarFileArchive(
new File(launchCommand.getExecutableArkBizJar().getFile())),
launchCommand.getExecutableArkBizJar());
// 创建Ark容器并启动
return new ArkContainer(executableArchive, launchCommand).start();
} else {
ClassPathArchive classPathArchive = new ClassPathArchive(
launchCommand.getEntryClassName(), launchCommand.getEntryMethodName(),
launchCommand.getEntryMethodDescriptor(), launchCommand.getClasspath());
return new ArkContainer(classPathArchive, launchCommand).start();
}
} catch (IOException e) {
throw new ArkException(String.format("SOFAArk startup failed, commandline=%s",
LaunchCommand.toString(args)), e);
}
}
ArkContainer(executableArchive, launchCommand).start()方法
arkServiceContainer.start()
public void start() throws ArkException {
if (started.compareAndSet(false, true)) {
ClassLoader oldClassloader = ClassloaderUtils.pushContextClassloader(getClass()
.getClassLoader());
try {
LOGGER.info("Begin to start ArkServiceContainer");
injector = Guice.createInjector(findServiceModules());
for (Binding<ArkService> binding : injector
.findBindingsByType(new TypeLiteral<ArkService>() {
})) {
arkServiceList.add(binding.getProvider().get());
}
Collections.sort(arkServiceList, new OrderComparator());
for (ArkService arkService : arkServiceList) {
LOGGER.info(String.format("Init Service: %s", arkService.getClass().getName()));
arkService.init();
}
ArkServiceContainerHolder.setContainer(this);
LOGGER.info("Finish to start ArkServiceContainer");
} finally {
ClassloaderUtils.popContextClassloader(oldClassloader);
}
}
}
##参考: