`
chenjingbo
  • 浏览: 456408 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

查看工程载入哪些class文件

 
阅读更多

     头段时间,在线上发布遇到一个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 里写

 

分享到:
评论

相关推荐

    面试必问之jvm与性能优化

    类加载器本身也是一个类,而它的工作就是把class文件从硬盘读取到内存中。在写程序的时候,我们几乎不需要关心类的加载,因为这些都是隐式装载的,除非我们有特殊的用法,像是反射,就需要显式的加载所需要的类。 ...

    php数据库类

    系统会自动载入 dedesql.class.php 文件,并用 $dsql = $db = new DedeSql(false); 进行初始化数据库连接,因此在工程所有文件中均不需要单独初始化这个类,可直接用 $dsql 或 $db 进行操作,为了防止错误,操作完后...

    信息管理系统课程设计报告.doc

    1 4.2.1 概念结构设计 1 4.2.2 逻辑结构设计 5 4.2.3 物理结构设计 5 4.3系统实施 7 4.3.1数据库实现 7 4.3.2 数据载入 9 4.4运行与测试 10 4.4.1运行与测试 10 4.4.2分析 12 5总结与展望 13 参考文献 14 "1 设计...

    ASP.NET的网页代码模型及生命周期

    public partial class _Default : System.Web.UI.Page //继承自System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } } 上述代码为Default.apx.cs页面代码。从上述代码可以看出...

    PHP和MySQL Web开发第4版pdf以及源码

    3.9 从文件载入数组 3.10 执行其他的数组操作 3.10.1 在数组中浏览:each()、current()、reset()、end()、next()、pos()和prev() 3.10.2 对数组的每一个元素应用任何函数:array_walk() 3.10.3 统计数组元素个数...

    PHP和MySQL Web开发第4版

    3.9 从文件载入数组 3.10 执行其他的数组操作 3.10.1 在数组中浏览:each()、current()、reset()、end()、next()、pos()和prev() 3.10.2 对数组的每一个元素应用任何函数:array_walk() 3.10.3 统计数组元素个数...

    PHP和MySQL WEB开发(第4版)

    3.9 从文件载入数组 3.10 执行其他的数组操作 3.10.1 在数组中浏览:each()、current()、reset()、end()、next()、pos()和prev() 3.10.2 对数组的每一个元素应用任何函数:array_walk() 3.10.3 统计数组元素个数:...

    jeasyui的dataGrid的打印和导出,jeasyui报表 table转成excel 实例下载

    如题,项目要用到jeasyui,所以必须要下载它的demo,获取相应的js,css等等的文件 jeasyui的下载地址:http://www.jeasyui.com/download/index.php &lt;!DOCTYPE ...

    CheckMem.pas

    B)、修改工程文件,将'CheckMem.pas'放到uses下的第一句 program Project1; uses CheckMem in 'CheckMem.pas', Forms, Unit1 in 'Unit1.pas' {Form1} ;//其他单元文件 {$R *.RES} begin Application....

    flash在C#中的应用

    public class FlashRightKey : AxShockwaveFlashObjects.AxShockwaveFlash { //定义一个公共类FlashRightKey(类名自己定义)来继承AxShockwaveFlashObjects.AxShockwaveFlash(在实例化Shockwave Flash Object控件...

    HGE_系列教材(1-9)

    首先建立一个空的Win32 工程,然后选择Project-&gt;Settings...-&gt;Link 按图所示,输入hge.lib 和hgehelp.lib 当然,也可以使用预编译器指令pragram 来打到同样的目的。 HGE 系列教材(3) --- 初试 HGE 当HGE 安装完成...

    Visual C++ 6 .0 多媒体开发指南.pdf

    1 .2 .1 工程工作区....................... 2 1 .2 .2 Developer Studio 的菜单体系............... 6 1 .3 使用ClassWizard ........................ 20 1 .3 .1 Message Maps 标签................... 20 1 .3 ....

Global site tag (gtag.js) - Google Analytics