头段时间,在线上发布遇到一个class not found的问题.纠结了好久..虽然有很多工具可以查看到对应载入的class.比如在启动的时候添加 -verbose 参数(等同于 -XX:+TraceClassLoading 和 ◦-XX:+TraceClassUnloading) 或者 下载一个对应类加载跟踪的agent(比如 这个jvm类跟踪器 ),或者直接用JVMTI拦截等等.但是,上面所有的方法,都需要依赖PE,然后重启应用.这个成本相对来说是比较高的(PE同学不一定允许你指定agent代理呢)..所以我就琢磨着,做一个小工具,可以直接查看当前应用载入的class类.
该工具依赖以下技术:
1 JavaAgent(JDK5以后提供),单独这个肯定不行,因为还是需要指定代理和重启
2 Java Tools API 中的 Attach API (JDK6以后才提供的).
上面两个依赖,就间接要求必须依赖tools.jar..所以如果线上环境是用JRE跑的话,需要自己依赖tools.jar.注意windows版本的tools.jar和linux版本的tools.jar是不一样的...
做法相当简单.
1 首先下载附件中的agent.然后放到你的工程classpath.该agent的源码如下,很简单
package com.taobao.ju.agent.tool; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.lang.instrument.Instrumentation; import java.util.ArrayList; import java.util.List; /** * User: zhenghui * Date: 13-10-29 * Time: 下午4:46 */ public class LoadedClassAgent { public static void agentmain(String args, Instrumentation inst)throws Exception { System.out.println("LoadedClassAgent agentmain attach..."); if(args == null || "".equals(args)){ args = "/home/admin/load_class_agent_temp.txt"; } System.getProperties().setProperty("monitor.conf.loadAgentFile",args); List<String> msgList = new ArrayList<String>(); for (Class clazz :inst.getAllLoadedClasses()){ msgList.add(clazz.getName()); } File file = new File(args); writeToFile(msgList,file); System.out.println("LoadedClassAgent agentmain end..."); } private static void writeToFile(List<String> msgList,File file) throws IOException { FileWriter fileWriter = new FileWriter(file); for(String msg : msgList){ fileWriter.write(msg); fileWriter.write('\r'); fileWriter.write('\n'); } fileWriter.close(); } }
agent需要自己打包,我是用maven打包的,所以顺便发一下对应的pom.xml. .注意看加红部分的设置..如果是自己打包,对应的META-INF的MANIFEST.MF里别忘了加这几项
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.taobao</groupId> <artifactId>parent</artifactId> <version>1.0.1</version> </parent> <groupId>com.taobao.ju</groupId> <artifactId>ju-agent-tool</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>jar</packaging> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifest> <addDefaultImplementationEntries>true</addDefaultImplementationEntries> <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries> </manifest> <manifestEntries> <Agent-Class>com.taobao.ju.agent.tool.LoadedClassAgent</Agent-Class> <Can-Redefine-Classes>true</Can-Redefine-Classes> <Can-Retransform-Classes>true</Can-Retransform-Classes> </manifestEntries> </archive> </configuration> </plugin> </plugins> </build> </project>
2 动态load 该agent.然后页面输出.下面是我的源码,注意一下,我是用webx作为mvc框架的.如果使用其他的框架,照着里面的代码自己改就OK.
package com.taobao.juwl.iserver.web.module.screen.tool; import com.alibaba.citrus.turbine.Context; import com.alibaba.citrus.turbine.Navigator; import com.alibaba.citrus.turbine.TurbineRunData; import com.alibaba.common.lang.StringUtil; import com.google.common.collect.Lists; import com.sun.tools.attach.VirtualMachine; import com.taobao.ju.agent.tool.LoadedClassAgent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.BufferedReader; import java.io.FileReader; import java.lang.management.ManagementFactory; import java.util.List; import java.util.Properties; /** * User: zhenghui * Date: 13-10-30 * Time: 上午10:16 */ public class LoadedClassView { private static final Logger log = LoggerFactory.getLogger(LoadedClassView.class); private static final String ENV_WINDOWS = "windows"; private static final String ENV_LINUX = "linux"; public void execute(TurbineRunData turbineRunData, Navigator nav, Context context) { try { Properties properties = System.getProperties(); VirtualMachine virtualMachine = VirtualMachine.attach(getPid()); virtualMachine.loadAgent(getAgentJar()); Thread.sleep(1000); virtualMachine.detach(); String fileName = (String) properties.get("monitor.conf.loadAgentFile"); if (StringUtil.isBlank(fileName)) { return; } FileReader fileReader = new FileReader(fileName); //最后的结果就放在loadedClasses里 List<String> loadedClasses = Lists.newArrayList(); BufferedReader bufferedReader = new BufferedReader(fileReader); String s; while ((s = bufferedReader.readLine()) != null) { loadedClasses.add(s); } bufferedReader.close(); context.put("loadedClasses", loadedClasses); } catch (Throwable e) { log.error("LoadedClassView error", e); } } private static String getPid() { String name = ManagementFactory.getRuntimeMXBean().getName(); String pid = name.split("@")[0]; return pid; } /** * 获取agent jar包所在的地址 * * @return */ private static String getAgentJar() { String path = LoadedClassAgent.class.getResource("").getFile(); if (path != null) { path = path.replace("!/com/taobao/ju/agent/tool/", ""); //如果是windows 则去除 "file:/" 如果是linux 则去除 "file:" if(ENV_WINDOWS.equals(getOSEnv())){ path = path.replace("file:/",""); } else { path = path.replace("file:",""); } } return path; } /** * 买不起mac,所以不知道mac是怎么设置的 :< * @return */ private static String getOSEnv(){ String osName = System.getProperty("os.name"); if(osName.toLowerCase().contains("windows")){ return ENV_WINDOWS; } else { return ENV_LINUX; } } }
数据获取到了,如何展现就看自己咯..我就是直接for循环打印了.哈哈
#if($!loadedClasses) #foreach($clazz in $!loadedClasses) $!clazz <br> #end #end
最后说明一下,如果说线上的应用,只有JRE,没有JDK的话,需要在classpath加一个 tools.jar..
参考资料 http://www.ibm.com/developerworks/cn/java/j-lo-jse61/index.html
最后说明一下如何用maven依赖tools.jar吧..遇到了很多问题.不过终于算解决了.首先,maven仓库中必须有windows和linux的tool.jar. 然后通过maven的profile去区别..
<profile> <id>product</id> <properties> <filterFile>${basedir}/../antx.properties</filterFile> <skipTgzPackage>false</skipTgzPackage> <toolsVersion>1.6-linux</toolsVersion> </properties> <activation> <activeByDefault>true</activeByDefault> </activation> </profile> <profile> <id>dev_win</id> <properties> <filterFile>${basedir}/src/main/filter/dev-filter.properties</filterFile> <skipTgzPackage>true</skipTgzPackage> <toolsVersion>1.6</toolsVersion> </properties> <activation> <os> <family>windows</family> </os> </activation> </profile>
默认是linux版的tools.jar.如果是windows,则依赖 windows的tools.jar.这里只指定了版本号.具体的依赖到dependency 里写
相关推荐
1. **使用ActiveX控件**:可以找寻支持PNG的第三方ActiveX控件,如GdipImage控件,将其添加到VB6.0工程中,然后通过控件的方法和属性来加载和显示PNG图片。例如,`GdipImage1.Picture = LoadPicture("path_to_your_...
这个工具的主要功能是在Mac平台上对Java的.class文件进行反编译,以帮助开发者理解和调试Java应用程序。`jd-gui`具有用户友好的图形界面,使得操作更为直观和简单。 描述中提到“mac版本反编译工具jd-gui”,这暗示...
类加载器本身也是一个类,而它的工作就是把class文件从硬盘读取到内存中。在写程序的时候,我们几乎不需要关心类的加载,因为这些都是隐式装载的,除非我们有特殊的用法,像是反射,就需要显式的加载所需要的类。 ...
1. 配置数据库路径:在Config菜单中选择set database path,指向tst\database_classb下的对应数据库文件。 2. 设置logging模式:在Control菜单中选择Logging,配置logging对话框。 3. 配置通信端口:在Config -> ...
系统会自动载入 dedesql.class.php 文件,并用 $dsql = $db = new DedeSql(false); 进行初始化数据库连接,因此在工程所有文件中均不需要单独初始化这个类,可直接用 $dsql 或 $db 进行操作,为了防止错误,操作完后...
2. **Pclass**:乘客的船舱等级,1为头等舱,2为二等舱,3为三等舱,反映了社会经济地位。 3. **Name**:乘客姓名,包含头衔信息,如先生、夫人等。 4. **Sex**:乘客性别。 5. **Age**:乘客年龄,部分缺失。 6. **...
此外,工程图样库以DWF格式存放,用户还需安装浏览器插件,例如AutoDesk的ExpressViewerSetup软件,以支持DWF格式文件的浏览。为了获得最佳的视觉效果,建议用户将计算机屏幕分辨率设置为1024x768。 4. 网页程序...
public partial class _Default : System.Web.UI.Page //继承自System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } } 上述代码为Default.apx.cs页面代码。从上述代码可以看出...
1. 加载分类器:使用 OpenCV 库提供的“haarcascade_frontalface_alt.xml”文件存储的目标检测分类,用 cvLoad 函数载入后,进展强制类型转换。 2. 加载待检测图象:加载待检测的图象,使用 OpenCV 库提供的函数 ...
3.9 从文件载入数组 3.10 执行其他的数组操作 3.10.1 在数组中浏览:each()、current()、reset()、end()、next()、pos()和prev() 3.10.2 对数组的每一个元素应用任何函数:array_walk() 3.10.3 统计数组元素个数...
3.9 从文件载入数组 3.10 执行其他的数组操作 3.10.1 在数组中浏览:each()、current()、reset()、end()、next()、pos()和prev() 3.10.2 对数组的每一个元素应用任何函数:array_walk() 3.10.3 统计数组元素个数...
3.9 从文件载入数组 3.10 执行其他的数组操作 3.10.1 在数组中浏览:each()、current()、reset()、end()、next()、pos()和prev() 3.10.2 对数组的每一个元素应用任何函数:array_walk() 3.10.3 统计数组元素个数:...
Console.WriteLine("正在载入MATLAB for .NET库"); DotNetTest.DotNetTestClass dt = new DotNetTest.DotNetTestClass(); Console.WriteLine("完成"); // 多项式 int dimension = 3; double[] dd = new ...
接着进入Android-Level阶段,该阶段由init进程开始,它会启动init.rc配置文件,并根据配置启动一些重要的外部程序,如servicemanager、Zygote进程以及SystemServer。servicemanager是Android的IPC(进程间通信)服务...
在软件工程中,单例模式保证一个类只有一个实例,并提供一个全局访问点。这个设计模式在许多场景下都很实用,比如数据库连接、配置管理等,因为这些对象通常需要在整个应用程序生命周期内保持一致。 在Qml中,`...
5. **使用步骤**:首先,将解压后的libsvm-3.22文件夹放置到MATLAB的路径下,然后在MATLAB环境中,载入对应的.m文件,加载数据,设置参数,调用训练和预测函数。 6. **参数调优**:SVM的性能很大程度上依赖于参数的...
如题,项目要用到jeasyui,所以必须要下载它的demo,获取相应的js,css等等的文件 jeasyui的下载地址:http://www.jeasyui.com/download/index.php <!DOCTYPE ...
B)、修改工程文件,将'CheckMem.pas'放到uses下的第一句 program Project1; uses CheckMem in 'CheckMem.pas', Forms, Unit1 in 'Unit1.pas' {Form1} ;//其他单元文件 {$R *.RES} begin Application....
14. 定义一个类名为"MyClass.java",并且该类可被一个工程中的所有类访问,其正确声明应为:(A) public class MyClass extends Object。public关键字使得类对所有类可见,而Java中的所有类默认都继承自Object类。 ...