获取程序启动类

server/2024/12/28 9:29:40/

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

    首先根据系统参数 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)) ;}
}

 


http://www.ppmy.cn/server/153874.html

相关文章

vue3入门教程:ref能否完全替代reactive?

1. 使用场景与数据类型 ref&#xff1a; 主要用于基本数据类型&#xff08;如String、Number、Boolean等&#xff09;。也可以用于对象/数组&#xff0c;但需要通过.value访问。适合单个响应式数据的管理。 reactive&#xff1a; 主要用于对象类型&#xff08;如Object、Array…

OPPO Java面试题及参考答案

Java 语言的特点 Java 是一种面向对象的编程语言,它具有以下显著特点。 首先是简单性。Java 的语法相对简单,它摒弃了 C 和 C++ 语言中一些复杂的特性,比如指针操作。这使得程序员能够更专注于业务逻辑的实现,而不是陷入复杂的语法细节中。例如,Java 的内存管理是自动进行…

python中Windows系统使用 pywin32 来复制图像到剪贴板,并使用 Selenium 模拟 Ctrl+V 操作

步骤 1&#xff1a;安装必要的库 首先&#xff0c;安装 pywin32 和 selenium&#xff1a; pip install pywin32 selenium 如果使用的是 macOS&#xff0c;可以安装 pyobjc&#xff1a; pip install pyobjc 步骤 2&#xff1a;使用 pywin32 复制图像到剪贴板 在 Windows 系统中…

SQL创建和操纵表

本文介绍创建、更改和删除表的基本知识。 1. 创建表 SQL 不仅用于表数据操纵&#xff0c;而且还用来执行数据库和表的所有操作&#xff0c;包括表本身的创建和处理。一般有两种创建表的方法&#xff1a; 多数DBMS 都具有交互式创建和管理数据库表的工具&#xff1b;表也可以…

题解:CF373B Making Sequences is Fun

思路 我们拿到这一题可以发现&#xff0c;可以使用二分查找。 bool check(ll x) {ll sum0;for(int im;i<mx;i){sumsumk*h(i);if(sum>n){return 0;}}return 1; }如果 check 函数这样写&#xff0c;那代码就算用了二分优化也一定会超时。那我们可以考虑如何优化 check 函…

Docker-构建自己的Web-Linux系统-镜像webtop:ubuntu-kde

介绍 安装自己的linux-server,可以作为学习使用&#xff0c;web方式访问&#xff0c;基于ubuntu构建开源项目 https://github.com/linuxserver/docker-webtop安装 docker run -d -p 1336:3000 -e PASSWORD123456 --name webtop lscr.io/linuxserver/webtop:ubuntu-kde登录 …

将多个 k8s yaml 配置文件合并为一个文件

如下bash脚本实现功能 “将多个k8s的yaml 配置文件” 合并为一个 yaml&#xff0c;使用 --- 分割文件配置。 创建文件 merge_yaml.sh &#xff0c;内容如下&#xff1a; #!/bin/bash# 默认参数 input_patterns() # 匹配的文件模式数组 output_file"combined.yaml"…

箭头函数与普通函数的区别

箭头函数&#xff08;Arrow Functions&#xff09;是ES6&#xff08;ECMAScript 2015&#xff09;引入的一种新的函数定义方式&#xff0c;它提供了更简洁的语法和一些与传统函数表达式不同的行为。 以下是箭头函数与普通函数的主要区别&#xff1a; 语法上的简化&#xff1a; …