您的位置 首页 java

Java,实战,模拟SpringBoot执行jar包启动原理

背景

一个应用了多年的自己编写的java的启动方式,觉得甚是方便,大致与SpringBoot启动jar的方式类似,于是就想把它共享出来,共勉之。

启动时序:

核心类图:

代码共享

java核心源码:

 package com.what21;

import java.io. file ;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;

public class BootstrapClassLoader extends URLClassLoader {

static final String JAR = ".jar";

static final String ZIP = ".zip";

public BootstrapClassLoader(URL[] urls) {
super(urls);
}

public static class Build {

/**
 * @param parentPath
 * @return
 */public static BootstrapClassLoader build(String parentPath) {
URL[] urls = toURL(parentPath);
// System.out.println(Arrays.toString(urls));
return new BootstrapClassLoader(urls);
}

/**
 * @param parentPath
 * @return
 */public static URL[] toURL(String parentPath) {
if (parentPath == null) {
return null;
}
File file = new File(parentPath);
if (!file.exists()) {
return null;
}
List<String> pathList = new ArrayList<String>();
listFile(parentPath, pathList);
URL[] urlArray = new URL[pathList.size()];
for (int i = 0; i < pathList.size(); i++) {
try {
urlArray[i] = new URL("file:///" + pathList.get(i));
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
return urlArray;
}

/**
 * @param filePath
 * @param pathList
 */static void listFile(String filePath, List<String> pathList) {
File file = new File(filePath);
File[] files = file.listFiles();
for (File subFile : files) {
recursionFile(subFile.getAbsolutePath(), pathList);
}
}

/**
 * @param filePath
 * @param pathList
 */static void recursionFile(String filePath, List<String> pathList) {
File file = new File(filePath);
if (file.isDirectory()) {
for (File subFile : file.listFiles()) {
listFile(subFile.getAbsolutePath(), pathList);
}
} else {
String absolutePath = file.getAbsolutePath().toLowerCase();
if (absolutePath.endsWith(".jar") || absolutePath.endsWith(".zip")) {
pathList.add(file.getAbsolutePath());
}
}
}

}

}  
 package com.what21;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Method;
import java.net.URL decode r;
import java.util.ArrayList;
import java.util.List;

public final class Bootstrap {

private static final String  bin  = "bin";
private static final String LIB = "lib";
private static final String APPS = "apps";
private static final String  launch Class = "com.what21.apps.ApplicationBootstrap";
private static final String launchMethod = "launch";
private static BootstrapClassLoader bootstrapClassLoader;

/**
 * @return
 */private static String  application Home() {
// 获取当前系统编码
String  encoding  = System.getProperty("sun.jnu.encoding");
if (encoding == null || "".equals(encoding)) {
encoding = "UTF-8";
}
// 获取URL,进行解码
String runPath = Bootstrap.class.getProtectionDomain().getCodeSource().getLocation().getPath();
String decodeRunPath = null;
try {
decodeRunPath = URLDecoder.decode(runPath, encoding);
} catch (Exception e) {

}
File runFile = new File(decodeRunPath);
if (!runFile.exists()) {
try {
decodeRunPath = URLDecoder.decode(runPath, "UTF-8");
} catch (Exception e) {

}
runFile = new File(decodeRunPath);
}
File runHomeFile = runFile.getParentFile();
String homePath = "";
if (BIN.equalsIgnoreCase(runHomeFile.getName())) {
homePath = runHomeFile.getParent();
} else {
homePath = runHomeFile.getAbsolutePath();
}
return homePath;
}

/**
 * @param obj
 */private static void logger(Object obj) {
System.out.println(obj);
}

/**
 * @param pidPath
 * @param pid
 */private static void writeProcessPid(String pidPath, String pid) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(new File(pidPath));
fos.write(pid.getBytes());
fos.flush();
} catch (Exception e) {
System.err.println(e.getMessage());
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
fos = null;
}
}
}

/**
 * @param applicationApps
 * @return
 */private static String[] toApplicationArray(String applicationApps) {
List<String> appList = new ArrayList<String>();
File appsFile = new File(applicationApps);
if (appsFile != null) {
File[] appFileArray = appsFile.listFiles();
for (File appFile : appFileArray) {
if (appFile.isDirectory()) {
appList.add(appFile.getAbsolutePath());
}
}
}
return appList.toArray(new String[] {});
}

/**
 * @param args
 */public static void main(String[] args) {
long startTime = System.currentTimeMillis();
logger("/////////////////////////////////////////////////////////////////////////////////////////////");
logger("/////////////////////////////////////////////////////////////////////////////////////////////");
// logger("// sun.jnu.encoding: " + System.getProperty("sun.jnu.encoding"));
logger("// file.encoding: " + System.getProperty("file.encoding"));
// home
String applicationHome = applicationHome();
System.setProperty("application.home", applicationHome);
logger("// application.home: " + applicationHome);
// lib
String applicationLib = applicationHome + "/" + LIB + "/";
System.setProperty("application.lib", applicationLib);
logger("// application.lib: " + applicationLib);
// apps
String applicationApps = applicationHome + "/" + APPS + "/";
System.setProperty("application.apps", applicationApps);
logger("// application.apps: " + applicationApps);
bootstrapClassLoader = BootstrapClassLoader.Build.build(applicationLib);
logger("// application.classloader: " + bootstrapClassLoader);
logger("/////////////////////////////////////////////////////////////////////////////////////////////");
String[] applicationPathArray = toApplicationArray(applicationApps);
// invoke
try {
Class<? extends Object> clazz = bootstrapClassLoader.loadClass(launchClass);
Object object = clazz.newInstance();
Method method = clazz.getDeclaredMethod(launchMethod, new Class[] { String[].class });
method.setAccessible(true);
method.invoke(object, new Object[] { applicationPathArray });
} catch (Exception e) {
e.printStackTrace();
}
logger("/////////////////////////////////////////////////////////////////////////////////////////////");
String runName = ManagementFactory.getRuntimeMXBean().getName();
logger("// application.name: " + runName);
if (runName != null) {
String pid = runName.split("@")[0];
writeProcessPid(applicationHome + "/" + BIN + "/process.pid", pid);
}
long endTime = System.currentTimeMillis();
logger("// Application startup in " + (endTime - startTime) + " ms");
logger("/////////////////////////////////////////////////////////////////////////////////////////////");
logger("/////////////////////////////////////////////////////////////////////////////////////////////");
}

}  

Linux启动脚本:

 #!/bin/bash

#==========================================================================================
# export JAVA_HOME=/opt/java/jdk1.8.0_221
export PATH=$JAVA_HOME/bin:$PATH
export JAVA_OPTS="-Xmx1024M -Xms512M -XX:MaxPermSize=256m"
export JAVA_JAR="startup-single-2.0.jar"
export JAVA_MAIN="com.what21.startup.SingleStartUp"
export LAUNCH_CLASS="com.what21.simba.netserv.launch.NetServDaemon.launch"
export LAUNCH_ARGS=""
export WORK_HOME=$(dirname "$PWD")
#==========================================================================================
export CLASSPATH=.:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar:$CLASSPATH
#==========================================================================================
echo "Java Home <=====> $JAVA_HOME"
echo "JVM Parameters <=====> $JAVA_OPTS"
echo "Start Jar <=====> $JAVA_JAR"
echo "Start Class <=====> $JAVA_MAIN"
echo "Launch Class <=====> $LAUNCH_CLASS"
echo "Start Parameters <=====> $LAUNCH_ARGS"
echo "Execute Command <=====> $CMD"
#==========================================================================================
nohup $JAVA_HOME/bin/java -DWorkHome=$WORK_HOME $JAVA_OPTS -classpath "$CLASSPATH:./$JAVA_JAR" "$JAVA_MAIN" "$LAUNCH_CLASS" "$LAUNCH_ARGS" "$CMD" >/dev/null 2>&1 &
#==========================================================================================  

Windows启动脚本:

 @echo off

rem ========================================================================
rem set JAVA_HOME=D:MyAppsJavajdk1.8.0_131
set JAVA_OPTS="-Xmx1024M -Xms512M -XX:MaxPermSize=256m"
set JAVA_JAR="startup-single-2.0.jar"
set JAVA_MAIN="com.what21.startup.SingleStartUp"
set LAUNCH_CLASS="com.what21.simba.netserv.launch.NetServDaemon.launch"
set LAUNCH_ARGS=
rem ========================================================================
set CLASSPATH=.;%JAVA_HOME%libdt.jar;%JAVA_HOME%libtools.jar
set WORK_HOME=%cd%
rem ========================================================================
rem 接收传入参数 
rem ========================================================================

if "%1"=="" goto doStart
if "%1"=="start" goto doStart
if "%1"=="stop" goto doShutdown

rem ========================================================================

:doStart
set CMD=start
goto doExe

rem ========================================================================

:doShutdown
set CMD=stop
goto doExe

rem ========================================================================

:doExe
echo "================================================================================================================"
echo "Execute Directory <=====> %WORK_HOME%"
echo "Java Home <=====> %JAVA_HOME%"
echo "JVM Parameters <=====> %JAVA_OPTS%"
echo "Start Jar <=====> %JAVA_JAR%"
echo "Start Class <=====> %JAVA_MAIN%"
echo "Launch Class <=====> %LAUNCH_CLASS%"
echo "Start Parameters <=====> %LAUNCH_ARGS%"
echo "Execute Command <=====> %CMD%"
echo "================================================================================================================"

echo.
%JAVA_HOME%binjava -DWorkHome=$WORK_HOME "%JAVA_OPTS%" -classpath "%CLASSPATH%;%JAVA_JAR%" "%JAVA_MAIN%" "%LAUNCH_CLASS%" "%LAUNCH_ARGS%" "%CMD%" &
pause
goto end 

rem ========================================================================

:notParam
echo not params

rem ========================================================================

:end  

文章来源:智云一二三科技

文章标题:Java,实战,模拟SpringBoot执行jar包启动原理

文章地址:https://www.zhihuclub.com/192194.shtml

关于作者: 智云科技

热门文章

网站地图