获取程序启动类

当程序有多个启动入口时,需要根据不同的启动类来决定方法是否执行,此时就需要获取启动类。

首先根据系统参数 sun.java.command 来获取启动类,如果以jar包方式启动,则获取到的就是jar包名称,此时需要从线程栈中获取main方法或者从jar包的元数据中获取。

java代码如下:

java 复制代码
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

@Slf4j
public class MainClassUtil {

    private static String MAIN_CLASS ;

    /**
     * 忽略的第三方引导类启动
     */
    private static final Set<String> IGNORE_MAIN_CLASS = new HashSet<>(Arrays.asList("org.springframework.boot.loader.JarLauncher"
            , "org.springframework.boot.loader.WarLauncher", "org.springframework.boot.loader.PropertiesLauncher"));

    /**
     * 查找启动类
     * @return 找到返回具体的类名称,否则返回空
     */
    public static String getStartMainClass() {
        if (MAIN_CLASS != null && !MAIN_CLASS.isEmpty()) {
            return MAIN_CLASS;
        }
        // 系统参数
        String clazz = System.getProperty("sun.java.command");
        if (clazz.contains(".jar")) {
            // 通过堆栈跟踪
           clazz = fromStackTrace();
           // 通过 MANIFEST.MF 查找
            if(clazz == null || clazz.isEmpty()){
               clazz = fromJarFile();
            }
        }
        MAIN_CLASS = clazz;
        log.info("start class :{}",MAIN_CLASS);
        return clazz;
    }

    /**
     * 从jar文件 META-INF/MANIFEST.MF 获取
     * @return 启动类,未找到返回空
     */
    private static String fromJarFile() {
        String javaCmd = System.getProperty("sun.java.command");
        String jarName = javaCmd.substring(0,javaCmd.indexOf(".jar") + 4);
        String userDir = System.getProperty("user.dir");
        // 拼接全路径
        if(!jarName.contains("/") && !jarName.contains("\\")){
            jarName = userDir + File.separator + jarName;
        }
        String clazz = null;
        log.info("jarName-------{}",jarName);
        try(JarFile jarFile = new JarFile(jarName)){
            Manifest manifest = jarFile.getManifest();
            Attributes attributes = manifest.getMainAttributes();
            clazz = attributes.getValue("Main-Class");
            if(IGNORE_MAIN_CLASS.contains(clazz)){
                clazz = attributes.getValue("Start-Class");
            }
        }catch (Exception e){
            log.error("jar包解析异常",e);
        }
        return clazz;

    }

    /**
     * 栈内信息查找
     * @return 启动类,未找到返回空
     */
    private static String fromStackTrace(){
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        List<String> mainMethod = new ArrayList<>();
        String methodName, cl;
        for (StackTraceElement stack : stackTrace) {
            methodName = stack.getMethodName();
            cl = stack.getClassName();
            if ("main".equals(methodName) && !IGNORE_MAIN_CLASS.contains(cl)) {
                try {
                    if (hasStandardMain(cl)) {
                        mainMethod.add(cl);
                    }
                } catch (Exception ignore) {
                }
            }
        }
        log.info("包含main方法的类:{}",mainMethod);
        return mainMethod.isEmpty() ? null : mainMethod.get(mainMethod.size() - 1);
    }

    /**
     * 判断是否有main方法
     * @param clazz 类名
     * @return true 有 false 没有
     */
    private static boolean hasStandardMain(String clazz) throws Exception {
        Class<?> aClass = Class.forName(clazz);
        Method main = aClass.getDeclaredMethod("main", String[].class);
        Class<?> returnType = main.getReturnType();
        int modifiers = main.getModifiers();
        return Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers) && (returnType.equals(void.class) || returnType.equals(Void.class)) ;
    }
}
相关推荐
один but you11 分钟前
const和constexpr常量表达式
java·前端·javascript
码云数智-大飞13 分钟前
RAII 与智能指针深度拆解
java·前端·算法
云烟成雨TD22 分钟前
Agent Scope Java 2.x 系列【19】Harness:从零搭建 MySQL 文件系统
java·人工智能·agent
qq36219670524 分钟前
阿里裁员新消息(2026最新动态汇总)
java·开发语言·前端
a11177625 分钟前
“黑夜流星“个人引导页 网页html
java·前端·html
砚底藏山河32 分钟前
沪深A股:如何获取基金持股数据
java·python·数据分析·maven
代码改善世界40 分钟前
【C++进阶】C++11:列表初始化、右值引用与移动语义、完美转发全解析
java·开发语言·c++
AIGS0011 小时前
JBoltAI V4.5企业智能体平台:技术架构拆解
java·人工智能·ai大模型应用
一勺菠萝丶1 小时前
Maven SNAPSHOT 父 POM 无法解析问题排查
java·maven
少爷晚安。1 小时前
Java基础02_JDK&JRE下载安装及环境配置
java·开发语言