JAVA找出哪个类import了不存在的类
2026/6/11 5:44:53 网站建设 项目流程

JAVA找出哪个类import了不存在的类

1. 背景

在JAVA中一个类A,import 另外的一个类B.然后在容器启动时,只会提示B类不存在,不会出现任何A类相关的信息 Tomcat中错误信息如下,测试代码使用org.slf4j.Logger说明 ,部分错误信息如下

at java.lang.Thread.run(Thread.java:748) Caused by: java.lang.NoClassDefFoundError: Lorg/slf4j/Logger; at java.lang.Class.getDeclaredFields0(Native Method) at java.lang.Class.privateGetDeclaredFields(Class.java:2583) ... 10 more Caused by: java.lang.ClassNotFoundException: org.slf4j.Logger at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1360) at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1182) ... 23 more

2. 日志能解决吗

在容器TOMCAT为类WebappClassLoaderBase开启详细日志,在/conf/logging.properties 添加如下日志

org.apache.catalina.loader.WebappClassLoaderBase.level = FINE

加上日志以后,输出内容如下

org.apache.catalina.loader.WebappClassLoaderBase.loadClass Loading class from local repository org.apache.catalina.loader.WebappClassLoaderBase.loadClass loadClass(dxxs.BTestClass, false) org.apache.catalina.loader.WebappClassLoaderBase.loadClass Searching local repositories org.apache.catalina.loader.WebappClassLoaderBase.findClass findClass(dxxs.BTestClass) org.apache.catalina.loader.WebappClassLoaderBase.loadClass Loading class from local repository org.apache.catalina.loader.WebappClassLoaderBase.loadClass loadClass(org.slf4j.Logger, false) org.apache.catalina.loader.WebappClassLoaderBase.loadClass Searching local repositories org.apache.catalina.loader.WebappClassLoaderBase.findClass findClass(org.slf4j.Logger) org.apache.catalina.loader.WebappClassLoaderBase.findClass --> Returning ClassNotFoundException

从日志输出上来看,只是知道dxxs.BTestClass后就加载org.slf4j.Logger,但并不能确定就是dxxs.BTestClass导致的

3. 分析字节码能解决吗

通过日志分析,感觉上是可以,但是不能确定.所以为了确定,采用 Java Agent 方式分析,当前加载的class是否引用了当前环境不存在的class

在TOMCAT启动时,配置参数,在启动时,注入编写jar

set JAVA_OPTS=%JAVA_OPTS% -javaagent:"%CATALINA_HOME%\lib\class-load-monitor-agent.jar"="%CATALINA_HOME%\conf\agent-config.properties"

再次启动后,对应输出内容如下

[ClassLoadMonitor] ========================================== [ClassLoadMonitor] FOUND REFERENCE TO MISSING CLASS: [ClassLoadMonitor] Source class: dxxs.BTestClass [ClassLoadMonitor] Missing class: org.slf4j.Logger [ClassLoadMonitor] ClassLoader: ParallelWebappClassLoader context: test delegate: false ----------> Parent Classloader: java.net.URLClassLoader@87aac27 [ClassLoadMonitor] Thread: localhost-startStop-1

这次从日志中,可以明确知道dxxs.BTestClass引用了类org.slf4j.Logger,而当前环境中却不存在org.slf4j.Logger.由此问题解决

4. 如何实现

构建配置,实现javaagent,需要在MANIFEST.MF文件中配置Premain-ClassAgent-Class,所有当前pom.xml构建配置信息如下

<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>3.2.0</version> <configuration> <archive> <manifestEntries> <Premain-Class>com.example.ClassLoadMonitorAgent</Premain-Class> <Agent-Class>com.example.ClassLoadMonitorAgent</Agent-Class> <Can-Redefine-Classes>true</Can-Redefine-Classes> <Can-Retransform-Classes>true</Can-Retransform-Classes> </manifestEntries> </archive> </configuration> </plugin>

这个代码中实现两个方法

public static void premain(String agentArgs, Instrumentation inst); public static void agentmain(String agentArgs, Instrumentation inst)

添加类加载转换器

inst.addTransformer(new ClassFileTransformer() { @Override public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { if (className != null && classfileBuffer != null) { String fullClassName = className.replace('/', '.'); if (!checkedClasses.contains(fullClassName)) { checkedClasses.add(fullClassName); analyzeBytecode(fullClassName, classfileBuffer, loader); } } return classfileBuffer; } }, true);

核心分析类分析代码analyzeBytecode关于常量池信息参考,可以查看地址docs.oracle.com/javase/spec…

private static void analyzeBytecode(String className, byte[] bytecode, ClassLoader loader) { try { DataInputStream dis = new DataInputStream(new ByteArrayInputStream(bytecode)); int magic = dis.readInt(); if (magic != 0xCAFEBABE) { return; } dis.readShort(); dis.readShort(); int constantPoolCount = dis.readShort(); String[] utf8Pool = new String[constantPoolCount]; int[] classRefIndices = new int[constantPoolCount]; int classRefCount = 0; for (int i = 1; i < constantPoolCount; i++) { byte tag = dis.readByte(); switch (tag) { case 1: // UTF8 utf8Pool[i] = dis.readUTF(); break; case 7: // Class int nameIndex = dis.readShort(); classRefIndices[classRefCount++] = nameIndex; break; case 8: // String dis.readShort(); break; case 9: // Fieldref case 10: // Methodref case 11: // InterfaceMethodref case 12: // NameAndType dis.readShort(); dis.readShort(); break; case 3: // Integer case 4: // Float dis.readInt(); break; case 5: // Long case 6: // Double dis.readLong(); i++; break; case 15: // MethodHandle dis.readByte(); dis.readShort(); break; case 16: // MethodType dis.readShort(); break; case 18: // InvokeDynamic dis.readShort(); dis.readShort(); break; default: break; } } for (int i = 0; i < classRefCount; i++) { int utf8Index = classRefIndices[i]; if (utf8Index > 0 && utf8Index < constantPoolCount && utf8Pool[utf8Index] != null) { // 小游戏 地心侠士 // 获取到当前class文件中引用类名 String referencedClass = utf8Pool[utf8Index].replace('/', '.'); // className 配置是要检查的的类名 checkReference(className, referencedClass, loader); } } // 小游戏 地心侠士 // 检查class文件,其他地方是否包含丢失的class scanForClassReferences(className, bytecode, loader); } catch (Exception e) { } } private static void scanForClassReferences(String className, byte[] bytecode, ClassLoader loader) { // 公众号: 小满小慢 for (String missingClass : missingClasses) { String internalName = missingClass.replace('.', '/'); String descriptorFormat = "L" + internalName + ";"; if (containsClassReference(bytecode, internalName) || containsClassReference(bytecode, descriptorFormat)) { logClassReference(className, missingClass, loader); } } }

如何使用?

  1. 生成配置文件agent-config.properties配置内容如下:# 小游戏 地心侠士 # 公众号 小满小漫 精心制作 # 配置需要监控的不存在的类,多个类用逗号或分号分隔 missingClasses=org.slf4j.Logger
  2. 修改启动参数 在catalina.bat文件中添加,agent配置信息,修改内容如下set JAVA_OPTS=%JAVA_OPTS% -javaagent:"%CATALINA_HOME%\lib\class-load-monitor-agent-1.0-SNAPSHOT.jar"="%CATAL

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询