spring-boot-maven-plugin:run分析

public void execute() throws MojoExecutionException, MojoFailureException {
    if (this.skip) {
        getLog().debug("skipping run as per configuration.");
        return;
    }
    run(getStartClass());
}

private String getStartClass() throws MojoExecutionException {
    String mainClass = this.mainClass;
    if (mainClass == null) {
        try {
            mainClass = MainClassFinder.findSingleMainClass(this.classesDirectory,
                    SPRING_BOOT_APPLICATION_CLASS_NAME);
        }
        catch (IOException ex) {
            throw new MojoExecutionException(ex.getMessage(), ex);
        }
    }
    if (mainClass == null) {
        throw new MojoExecutionException("Unable to find a suitable main class, please add a 'mainClass' property");
    }
    return mainClass;
}

这里涉及到到mainClass的寻找,参考:spring-boot-maven-plugin:repackage分析-CSDN博客,我们来看下run方法:

private void run(String startClassName) throws MojoExecutionException, MojoFailureException {
    boolean fork = isFork();
    this.project.getProperties().setProperty("_spring.boot.fork.enabled", Boolean.toString(fork));
    if (fork) {
        doRunWithForkedJvm(startClassName);
    }
    else {
        logDisabledFork();
        runWithMavenJvm(startClassName, resolveApplicationArguments().asArray());
    }
}
protected void logDisabledFork() {
    if (getLog().isWarnEnabled()) {
        if (hasAgent()) {
            getLog().warn("Fork mode disabled, ignoring agent");
        }
        if (hasJvmArgs()) {
            RunArguments runArguments = resolveJvmArguments();
            getLog().warn("Fork mode disabled, ignoring JVM argument(s) ["
                    + String.join(" ", runArguments.asArray()) + "]");
        }
        if (hasWorkingDirectorySet()) {
            getLog().warn("Fork mode disabled, ignoring working directory configuration");
        }
    }
}
先看doRunWithForkedJvm,fork模式启用,允许个性化定制参数
private void doRunWithForkedJvm(String startClassName) throws MojoExecutionException, MojoFailureException {
    List<String> args = new ArrayList<>();
    addAgents(args);
    addJvmArgs(args);
    addClasspath(args);
    args.add(startClassName);
    addArgs(args);
    runWithForkedJvm((this.workingDirectory != null) ? this.workingDirectory : this.project.getBasedir(), args,
                     determineEnvironmentVariables());
}
private void addAgents(List<String> args) {
    File[] configuredAgents = determineAgents();
    if (configuredAgents != null) {
        if (getLog().isInfoEnabled()) {
            getLog().info("Attaching agents: " + Arrays.asList(configuredAgents));
        }
        for (File agent : configuredAgents) {
            args.add("-javaagent:" + agent);
        }
    }
    if (this.noverify) {
        args.add("-noverify");
    }
}
private File[] determineAgents() {
	return (this.agents != null) ? this.agents : this.agent;
}

private void addJvmArgs(List<String> args) {
    RunArguments jvmArguments = resolveJvmArguments();
    Collections.addAll(args, jvmArguments.asArray());
    logArguments("JVM argument(s): ", jvmArguments.asArray());
}
protected RunArguments resolveJvmArguments() {
    StringBuilder stringBuilder = new StringBuilder();
    if (this.systemPropertyVariables != null) {
        stringBuilder.append(this.systemPropertyVariables.entrySet().stream()
                .map((e) -> SystemPropertyFormatter.format(e.getKey(), e.getValue()))
                .collect(Collectors.joining(" ")));
    }
    if (this.jvmArguments != null) {
        stringBuilder.append(" ").append(this.jvmArguments);
    }
    return new RunArguments(stringBuilder.toString());
}
static class SystemPropertyFormatter {
    static String format(String key, String value) {
        if (key == null) {
            return "";
        }
        if (value == null || value.isEmpty()) {
            return String.format("-D%s", key);
        }
        return String.format("-D%s=\"%s\"", key, value);
    }
}

private void addClasspath(List<String> args) throws MojoExecutionException {
    try {
        StringBuilder classpath = new StringBuilder();
        for (URL ele : getClassPathUrls()) {
            if (classpath.length() > 0) {
                classpath.append(File.pathSeparator);
            }
            classpath.append(new File(ele.toURI()));
        }
        if (getLog().isDebugEnabled()) {
            getLog().debug("Classpath for forked process: " + classpath);
        }
        args.add("-cp");//指示classPath路径
        args.add(classpath.toString());
    }
    catch (Exception ex) {
        throw new MojoExecutionException("Could not build classpath", ex);
    }
}

private void addArgs(List<String> args) {
    RunArguments applicationArguments = resolveApplicationArguments();
    Collections.addAll(args, applicationArguments.asArray());
    logArguments("Application argument(s): ", applicationArguments.asArray());
}
protected RunArguments resolveApplicationArguments() {
    RunArguments runArguments = (this.arguments != null) ? new RunArguments(this.arguments)
            : new RunArguments(this.commandlineArguments);
    addActiveProfileArgument(runArguments);
    return runArguments;
}
private void addActiveProfileArgument(RunArguments arguments) {
    if (this.profiles.length > 0) {
        StringBuilder arg = new StringBuilder("--spring.profiles.active=");
        for (int i = 0; i < this.profiles.length; i++) {
            arg.append(this.profiles[i]);
            if (i < this.profiles.length - 1) {
                arg.append(",");
            }
        }
        arguments.getArgs().addFirst(arg.toString());
        logArguments("Active profile(s): ", this.profiles);
    }
}
private Map<String, String> determineEnvironmentVariables() {
    EnvVariables envVariables = resolveEnvVariables();
    logArguments("Environment variable(s): ", envVariables.asArray());
    return envVariables.asMap();
}
protected EnvVariables resolveEnvVariables() {
    return new EnvVariables(this.environmentVariables);
}

可以看出这整个过程都是拼凑java参数,不多说,我们来看真正的执行方法:runWithForkedJvm

protected abstract void runWithForkedJvm(File workingDirectory, List<String> args,
                                         Map<String, String> environmentVariables) throws MojoExecutionException, MojoFailureException;

@Override
protected void runWithForkedJvm(File workingDirectory, List<String> args, Map<String, String> environmentVariables)
        throws MojoExecutionException {
    int exitCode = forkJvm(workingDirectory, args, environmentVariables);
    if (exitCode == 0 || exitCode == EXIT_CODE_SIGINT) {
        return;
    }
    throw new MojoExecutionException("Application finished with exit code: " + exitCode);
}

private int forkJvm(File workingDirectory, List<String> args, Map<String, String> environmentVariables)
        throws MojoExecutionException {
    try {
        RunProcess runProcess = new RunProcess(workingDirectory, new JavaExecutable().toString());
        Runtime.getRuntime().addShutdownHook(new Thread(new RunProcessKiller(runProcess)));
        return runProcess.run(true, args, environmentVariables);
    }
    catch (Exception ex) {
        throw new MojoExecutionException("Could not exec java", ex);
    }
}

可以看出执行的是RunProcess#run:

public int run(boolean waitForProcess, Collection<String> args, Map<String, String> environmentVariables)
throws IOException {
    ProcessBuilder builder = new ProcessBuilder(this.command);
    builder.directory(this.workingDirectory);
    builder.command().addAll(args);
    builder.environment().putAll(environmentVariables);
    builder.redirectErrorStream(true);
    builder.inheritIO();
    try {
        Process process = builder.start();
        this.process = process;
        SignalUtils.attachSignalHandler(this::handleSigInt);
        if (waitForProcess) {
            try {
                return process.waitFor();
            }
            catch (InterruptedException ex) {
                Thread.currentThread().interrupt();
                return 1;
            }
        }
        return 5;
    }
    finally {
        if (waitForProcess) {
            this.endTime = System.currentTimeMillis();
            this.process = null;
        }
    }
}

这个方法可以参考复用,还有JavaExecutable也可以复用

runWithMavenJvm(startClassName, resolveApplicationArguments().asArray());来看第二个分支
protected abstract void runWithMavenJvm(String startClassName, String... arguments)
throws MojoExecutionException, MojoFailureException;

protected void runWithMavenJvm(String startClassName, String... arguments) throws MojoExecutionException {
    IsolatedThreadGroup threadGroup = new IsolatedThreadGroup(startClassName);
    //LaunchRunner用于main的反射执行
    Thread launchThread = new Thread(threadGroup, new LaunchRunner(startClassName, arguments), "main");
    launchThread.setContextClassLoader(new URLClassLoader(getClassPathUrls()));
    launchThread.start();
    join(threadGroup);
    threadGroup.rethrowUncaughtException();
}

private void join(ThreadGroup threadGroup) {
    boolean hasNonDaemonThreads;
    //阻塞 等待所有线程执行完毕
    do {
        hasNonDaemonThreads = false;
        Thread[] threads = new Thread[threadGroup.activeCount()];
        //将活跃的线程加入到
        threadGroup.enumerate(threads);
        for (Thread thread : threads) {
            if (thread != null && !thread.isDaemon()) {
                try {
                    hasNonDaemonThreads = true;
                    thread.join();
                }
                catch (InterruptedException ex) {
                    Thread.currentThread().interrupt();
                }
            }
        }
    }
    while (hasNonDaemonThreads);
}

这里从maven切出一个线程来执行应用程序,而fork模式则是采用客户端java拼装java命令来执行

  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值