javaagent 实现切面监控

java agent 实现方法监控

首先先看一段main方法

public class Main {

    public static void main(String[] args) throws IOException, AttachNotSupportedException, AgentLoadException, AgentInitializationException {

        List<VirtualMachineDescriptor> listAfter = VirtualMachine.list();
        for (VirtualMachineDescriptor vmd : listAfter) {
            if (vmd.displayName().equals("com.dfire.soa.report.utils.Main")) {
                VirtualMachine attach = VirtualMachine.attach(vmd.id());
                attach.loadAgent("C:\\Users\\qinghao\\Desktop\\Java\\agent.jar");
                attach.detach();
                break;
            }
        }

             try {
                 TimeUnit.SECONDS.sleep(3);
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }

             Target target = new Target();
             target.doBusiness("dsad", "hndsjadsaa");
    }
}

1 其中 VirtualMachine.list() 用于获取当前系统中所有的java进程信息 由于我是要对Target.doBusiness 方法进行监控 所以 displayName == com.dfire.soa.report.utils.Main 即可 ( 注: VirtualMachine.list() 与 jps -mlvV 获取到的信息大致相同 感兴趣可以去看看 , 2种方式调用的底层应该是一样的 )

找到对应vmd.id() 这个便是当前main方法运行的进程ID

3 loadAgent 必须要打成jar的方式 注( 里面只有1个文件 ) 注意里面红色的部分 agent-class 是你需要attach 的类

Can-Retransform-Classess 这个属性非常的重要 否则会报错


4 detach

以上便完成了 虚拟机进程的attach

按照顺序 agent-class 该类是代理类 也就是jar -> MANIFEST.MF指定的文件

要实现虚拟机动态agent 需要代理类实现如下2个方法

一下2个方法是在 java.lang.ClassLoader#defineClass1之前被调用的 如图


agentmain(String agentArgs, Instrumentation inst) inst可以addTransformer来实现对虚拟机load clazz byte 的修改

agentmain(String agentArgs)

public class QingHao {
public static void agentmain(String agentArgs, Instrumentation inst) throws ClassNotFoundException, UnmodifiableClassException,
         InterruptedException {
            inst.addTransformer(new AgentClass(), true);
            inst.retransformClasses(AgentClass.class); 
               System.out.println("Agent Main Done");

         }
}

本次实现用的是javassist 处理字节码

大致思路将 Target 中doBusiness 方法重新封装一下 (Target类会在后面给出)

  • 将doBusiness的方法体拷贝到doBuesiness$Impl
  • 重新生成一个新doBusiness 的方法
  • 在新doBusiness方法中实现对参数 a,b 以及返回TargetReturn 对象的监控
public class AgentClass implements ClassFileTransformer {
  
    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {


        System.out.println(loader);
        System.out.println(className);
        System.out.println(classBeingRedefined);
        System.out.println(protectionDomain);
        System.out.println(classfileBuffer);


        if ("com/dfire/soa/report/utils/Target".equals(className)) {


            System.out.println(" Target --->>dsjadsads a");

            try {
                CtClass ctClass = ClassPool.getDefault().getCtClass("com.dfire.soa.report.utils.Target");

                System.out.println(ctClass);

                CtMethod ctMethod = ctClass.getDeclaredMethod("doBusiness");





                System.out.println(ctMethod);

                String name = ctMethod.getReturnType().getName();
                //拷贝一个方法
                CtMethod copy = CtNewMethod.copy(ctMethod ,"doBusiness", ctClass, null);

                System.out.println(copy.getName());
                String oldMethodName = "doBuesiness$Impl";
                ctMethod.setName(oldMethodName);
				// 对输入参数的监控
                ctMethod.insertBefore(("System.out.println(\"a 参数\" + a) ; System.out.println( \"b 参数\"+b) ;  "));

                System.out.println(ctMethod.getName());


                System.out.println( "----------->" );

                String st = ("{") ;
                st += (name + " xx = null;  " );
                st += ("xx = " + oldMethodName+"($$);");
                st += ("System.out.println( \" 执行结果\" + xx );");
                st += ("return xx;");// 返回的对象
                st += ("}");
                copy.setBody(st);
                ctClass.addMethod(copy);
                return ctClass.toBytecode();

            } catch (NotFoundException e) {
                e.printStackTrace();
            } catch (CannotCompileException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }


        }

//        if ("com.dfire.soa.report.utils.Target".equals(className)) {
//            ClassPool pool  =  ClassPool.getDefault();
//            CtClass cc  = null;
//            try {
//                cc = pool.get("com.dfire.soa.report.utils.Target");
//                CtMethod cm  =  cc.getDeclaredMethod( "doBusiness" );
//
//
                cm.insertBefore( );
//            } catch (NotFoundException e) {
//                e.printStackTrace();
//            }
//        }
        // return null 从原来class池里面取数据
        return null;
    }
}

上面类所用到的Target

public class Target {

 

    public TargetReturn doBusiness( String  a, String b ) {

        TargetReturn targetReturn = new TargetReturn();


        targetReturn.setA(a);
        targetReturn.setB(b);

        return targetReturn;
    }

}
public class TargetReturn {

    private String a ;
    private String b ;

    public String getA() {
        return a;
    }

    public void setA(String a) {
        this.a = a;
    }

    public String getB() {
        return b;
    }

    public void setB(String b) {
        this.b = b;
    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this);
    }
}

然后看最后的运行结果

[B@71a7217b

 Target --->>dsjadsads a

javassist.CtClassType@3003596d[public class com.dfire.soa.report.utils.Target fields= constructors=javassist.CtConstructor@4eae0e13[public Target ()V],  methods=javassist.CtMethod@4a2d9118[public doBusiness (Ljava/lang/String;Ljava/lang/String;)Lcom/dfire/soa/report/utils/TargetReturn;], ]

javassist.CtMethod@4a2d9118[public doBusiness (Ljava/lang/String;Ljava/lang/String;)Lcom/dfire/soa/report/utils/TargetReturn;]

doBusiness

doBuesiness$Impl

----------->

a 参数dsad

b 参数hndsjadsaa

sun.misc.Launcher$AppClassLoader@18b4aac2

com/dfire/soa/report/utils/TargetReturn

null

ProtectionDomain  (file:/D:/WorkSpaces/new_retail/retail-report-soa/retail-report-client/target/classes/ <no signer certificates>)

 sun.misc.Launcher$AppClassLoader@18b4aac2

 <no principals>

 java.security.Permissions@2c95d52c (

 ("java.io.FilePermission" "\D:\WorkSpaces\new_retail\retail-report-soa\retail-report-client\target\classes\-" "read")

 ("java.lang.RuntimePermission" "exitVM")

)





[B@49d733db

sun.misc.Launcher$AppClassLoader@18b4aac2

org/apache/commons/lang3/builder/ToStringBuilder

null

ProtectionDomain  (file:/D:/Storage/m2/repository/org/apache/commons/commons-lang3/3.7/commons-lang3-3.7.jar <no signer certificates>)

 sun.misc.Launcher$AppClassLoader@18b4aac2

 <no principals>

 java.security.Permissions@5c44c877 (

 ("java.io.FilePermission" "\D:\Storage\m2\repository\org\apache\commons\commons-lang3\3.7\commons-lang3-3.7.jar" "read")

 ("java.lang.RuntimePermission" "exitVM")

)





[B@8151e94

sun.misc.Launcher$AppClassLoader@18b4aac2

org/apache/commons/lang3/builder/Builder

null

ProtectionDomain  (file:/D:/Storage/m2/repository/org/apache/commons/commons-lang3/3.7/commons-lang3-3.7.jar <no signer certificates>)

 sun.misc.Launcher$AppClassLoader@18b4aac2

 <no principals>

 java.security.Permissions@5c44c877 (

 ("java.io.FilePermission" "\D:\Storage\m2\repository\org\apache\commons\commons-lang3\3.7\commons-lang3-3.7.jar" "read")

 ("java.lang.RuntimePermission" "exitVM")

)





[B@6c32a70c

sun.misc.Launcher$AppClassLoader@18b4aac2

org/apache/commons/lang3/builder/ToStringStyle

null

ProtectionDomain  (file:/D:/Storage/m2/repository/org/apache/commons/commons-lang3/3.7/commons-lang3-3.7.jar <no signer certificates>)

 sun.misc.Launcher$AppClassLoader@18b4aac2

 <no principals>

 java.security.Permissions@5c44c877 (

 ("java.io.FilePermission" "\D:\Storage\m2\repository\org\apache\commons\commons-lang3\3.7\commons-lang3-3.7.jar" "read")

 ("java.lang.RuntimePermission" "exitVM")

)





[B@4bf0fc83

sun.misc.Launcher$AppClassLoader@18b4aac2

org/apache/commons/lang3/builder/ToStringStyle$DefaultToStringStyle

null

ProtectionDomain  (file:/D:/Storage/m2/repository/org/apache/commons/commons-lang3/3.7/commons-lang3-3.7.jar <no signer certificates>)

 sun.misc.Launcher$AppClassLoader@18b4aac2

 <no principals>

 java.security.Permissions@5c44c877 (

 ("java.io.FilePermission" "\D:\Storage\m2\repository\org\apache\commons\commons-lang3\3.7\commons-lang3-3.7.jar" "read")

 ("java.lang.RuntimePermission" "exitVM")

)





[B@79ab212e

sun.misc.Launcher$AppClassLoader@18b4aac2

org/apache/commons/lang3/builder/ToStringStyle$MultiLineToStringStyle

null

ProtectionDomain  (file:/D:/Storage/m2/repository/org/apache/commons/commons-lang3/3.7/commons-lang3-3.7.jar <no signer certificates>)

 sun.misc.Launcher$AppClassLoader@18b4aac2

 <no principals>

 java.security.Permissions@5c44c877 (

 ("java.io.FilePermission" "\D:\Storage\m2\repository\org\apache\commons\commons-lang3\3.7\commons-lang3-3.7.jar" "read")

 ("java.lang.RuntimePermission" "exitVM")

)





[B@76dd6693

sun.misc.Launcher$AppClassLoader@18b4aac2

org/apache/commons/lang3/builder/ToStringStyle$NoFieldNameToStringStyle

null

ProtectionDomain  (file:/D:/Storage/m2/repository/org/apache/commons/commons-lang3/3.7/commons-lang3-3.7.jar <no signer certificates>)

 sun.misc.Launcher$AppClassLoader@18b4aac2

 <no principals>

 java.security.Permissions@5c44c877 (

 ("java.io.FilePermission" "\D:\Storage\m2\repository\org\apache\commons\commons-lang3\3.7\commons-lang3-3.7.jar" "read")

 ("java.lang.RuntimePermission" "exitVM")

)





[B@2f50f8b0

sun.misc.Launcher$AppClassLoader@18b4aac2

org/apache/commons/lang3/builder/ToStringStyle$ShortPrefixToStringStyle

null

ProtectionDomain  (file:/D:/Storage/m2/repository/org/apache/commons/commons-lang3/3.7/commons-lang3-3.7.jar <no signer certificates>)

 sun.misc.Launcher$AppClassLoader@18b4aac2

 <no principals>

 java.security.Permissions@5c44c877 (

 ("java.io.FilePermission" "\D:\Storage\m2\repository\org\apache\commons\commons-lang3\3.7\commons-lang3-3.7.jar" "read")

 ("java.lang.RuntimePermission" "exitVM")

)





[B@445d0c07

sun.misc.Launcher$AppClassLoader@18b4aac2

org/apache/commons/lang3/builder/ToStringStyle$SimpleToStringStyle

null

ProtectionDomain  (file:/D:/Storage/m2/repository/org/apache/commons/commons-lang3/3.7/commons-lang3-3.7.jar <no signer certificates>)

 sun.misc.Launcher$AppClassLoader@18b4aac2

 <no principals>

 java.security.Permissions@5c44c877 (

 ("java.io.FilePermission" "\D:\Storage\m2\repository\org\apache\commons\commons-lang3\3.7\commons-lang3-3.7.jar" "read")

 ("java.lang.RuntimePermission" "exitVM")

)





[B@23196e9b

sun.misc.Launcher$AppClassLoader@18b4aac2

org/apache/commons/lang3/builder/ToStringStyle$NoClassNameToStringStyle

null

ProtectionDomain  (file:/D:/Storage/m2/repository/org/apache/commons/commons-lang3/3.7/commons-lang3-3.7.jar <no signer certificates>)

 sun.misc.Launcher$AppClassLoader@18b4aac2

 <no principals>

 java.security.Permissions@5c44c877 (

 ("java.io.FilePermission" "\D:\Storage\m2\repository\org\apache\commons\commons-lang3\3.7\commons-lang3-3.7.jar" "read")

 ("java.lang.RuntimePermission" "exitVM")

)





[B@1b2bab38

sun.misc.Launcher$AppClassLoader@18b4aac2

org/apache/commons/lang3/builder/ToStringStyle$JsonToStringStyle

null

ProtectionDomain  (file:/D:/Storage/m2/repository/org/apache/commons/commons-lang3/3.7/commons-lang3-3.7.jar <no signer certificates>)

 sun.misc.Launcher$AppClassLoader@18b4aac2

 <no principals>

 java.security.Permissions@5c44c877 (

 ("java.io.FilePermission" "\D:\Storage\m2\repository\org\apache\commons\commons-lang3\3.7\commons-lang3-3.7.jar" "read")

 ("java.lang.RuntimePermission" "exitVM")

)





[B@139c3a05

sun.misc.Launcher$AppClassLoader@18b4aac2

org/apache/commons/lang3/builder/ReflectionToStringBuilder

null

ProtectionDomain  (file:/D:/Storage/m2/repository/org/apache/commons/commons-lang3/3.7/commons-lang3-3.7.jar <no signer certificates>)

 sun.misc.Launcher$AppClassLoader@18b4aac2

 <no principals>

 java.security.Permissions@5c44c877 (

 ("java.io.FilePermission" "\D:\Storage\m2\repository\org\apache\commons\commons-lang3\3.7\commons-lang3-3.7.jar" "read")

 ("java.lang.RuntimePermission" "exitVM")

)





[B@21ba4b9c

sun.misc.Launcher$AppClassLoader@18b4aac2

org/apache/commons/lang3/Validate

null

ProtectionDomain  (file:/D:/Storage/m2/repository/org/apache/commons/commons-lang3/3.7/commons-lang3-3.7.jar <no signer certificates>)

 sun.misc.Launcher$AppClassLoader@18b4aac2

 <no principals>

 java.security.Permissions@5c44c877 (

 ("java.io.FilePermission" "\D:\Storage\m2\repository\org\apache\commons\commons-lang3\3.7\commons-lang3-3.7.jar" "read")

 ("java.lang.RuntimePermission" "exitVM")

)





[B@61ba30b6

null

java/lang/IllegalStateException

null

null

[B@437e6a0a

sun.misc.Launcher$AppClassLoader@18b4aac2

org/apache/commons/lang3/builder/ToStringExclude

null

ProtectionDomain  (file:/D:/Storage/m2/repository/org/apache/commons/commons-lang3/3.7/commons-lang3-3.7.jar <no signer certificates>)

 sun.misc.Launcher$AppClassLoader@18b4aac2

 <no principals>

 java.security.Permissions@5c44c877 (

 ("java.io.FilePermission" "\D:\Storage\m2\repository\org\apache\commons\commons-lang3\3.7\commons-lang3-3.7.jar" "read")

 ("java.lang.RuntimePermission" "exitVM")

)





[B@55ad91c7

null

sun/reflect/annotation/AnnotationParser

null

null

[B@18774e30

null

sun/reflect/UnsafeObjectFieldAccessorImpl

null

null

[B@3513e002

执行结果com.dfire.soa.report.utils.TargetReturn@61df0988[a=dsad,b=hndsjadsaa]

​ 从执行结果来看有很多类的信息输出

总结

优点

  • 该实现可以动态agent 无需用jar -javaagent 的方式
  • 该实现对项目中编写的类无侵入性

缺点

  • Target 应该缓存起来
  • agent.jar 中manifest.mf的指定必须要以jar的形式指定

感谢小伙伴提供许多的文章 参考如下

http://blog.csdn.net/mousebaby808/article/details/37696371

https://www.ibm.com/developerworks/cn/java/j-dyn0916/

http://zheng12tian.iteye.com/blog/1495037

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值