zoukankan      html  css  js  c++  java
  • java 动态AOP

    一、實現機制:

    在运行期,所有类加载器加载字节码前,前进行拦截。並將代碼植入。可以对所有类进行织入。

    二、實現方式:

    1. 實現ClassFileTransformer 接口

    2. 添加以下方法(必須):

    public static void premain(String options, Instrumentation ins) {   
    //注册我自己的字节码转换器
    ins.addTransformer(new MyClassFileTransformer());
    }

    實例:

     1 package com.aop;
    2
    3 import java.io.IOException;
    4 import java.lang.instrument.ClassFileTransformer;
    5 import java.lang.instrument.IllegalClassFormatException;
    6 import java.lang.instrument.Instrumentation;
    7 import java.security.ProtectionDomain;
    8
    9 import javassist.CannotCompileException;
    10 import javassist.ClassPool;
    11 import javassist.CtClass;
    12 import javassist.CtMethod;
    13 import javassist.NotFoundException;
    14
    15 public class AopTransformer implements ClassFileTransformer {
    16
    17 /**
    18 * 字节码加载到虚拟机前会进入这个方法
    19 */
    20 @Override
    21 public byte[] transform(ClassLoader loader, String className,
    22 Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
    23 byte[] classfileBuffer) throws IllegalClassFormatException {
    24
    25 // javassist的包名是用点分割的,需要转换下
    26 if (className.indexOf("/") != -1) {
    27 className = className.replaceAll("/", ".");
    28 }
    29
    30 try {
    31 // 通过包名获取类文件
    32 CtClass cc = ClassPool.getDefault().get(className);
    33
    34 // 获得指定方法名的方法
    35 CtMethod m = cc.getDeclaredMethod("sayhello");
    36
    37 // 在方法执行前插入代码
    38 m.insertBefore("{System.out.println(\"在HelloTest.sayhello之前執行\");}");
    39 m.insertAfter("{System.out.println(\"在HelloTest.sayhello之後執行\");}");
    40 m = cc.getDeclaredMethod("sayGoodBye");
    41
    42 // 在方法执行前插入代码
    43 m.setBody("{System.out.println(\"修改HelloTest.sayGoodBye的方法體\");}");
    44 return cc.toBytecode();
    45 } catch (NotFoundException e) {
    46 } catch (CannotCompileException e) {
    47 e.printStackTrace();
    48 } catch (IOException e) {
    49 // 忽略异常处理
    50 }
    51 return null;
    52 }
    53
    54 /**
    55 * 在main函数执行前,执行的函数
    56 *
    57 * @param options
    58 * @param ins
    59 */
    60 public static void premain(String options, Instrumentation ins) {
    61 // 注册我自己的字节码转换器
    62 ins.addTransformer(new AopTransformer());
    63 }
    64 }
     1 package com.test;
    2
    3 public class HelloTest {
    4 public void sayhello() {
    5 System.out.println("HelloTest sayhello");
    6 }
    7 public void sayGoodBye() {
    8 System.out.println("HelloTest sayGoodBye");
    9 }
    10
    11 public static void main(String[] args) {
    12 HelloTest ht = new HelloTest();
    13 ht.sayhello();
    14 ht.sayGoodBye();
    15 }
    16 }


    三、執行

    1. 需要告诉JVM在启动main函数之前,需要先执行premain函数。首先需要将premain函数所在的类打成jar包。并修改该jar包里的META-INF\MANIFEST.MF 文件,MANIFEST.MF 文件內容如下:

    1 Manifest-Version: 1.0
    2 Premain-Class: com.aop.AopTransformer
    3 Can-Redefine-Classes: true
    4 Can-Retransform-Classes: true
    5 Can-Set-Native-Method-Prefix: true

    2. 將aop.jar放到同一目錄

    3. 使用java命令執行main方法:

    java -javaagent:.\aop.jar HelloTest

    4. 執行結果比較

    如果沒有添加aop執行結果如下:

    HelloTest sayhello
    HelloTest sayGoodBye

    添加aop執行結果如下:

    在HelloTest.sayhello之前執行
    HelloTest sayhello
    在HelloTest.sayhello之後執行
    修改HelloTest.sayGoodBye的方法體






     

  • 相关阅读:
    (OK) 交叉编译node-v4.2.1—for—android
    (OK) 交叉编译hello.c for android (--sysroot),不使用Android.mk和ndk-build
    (OK) port_lighttpd_to_Android——没有基于android 4.4源码
    (OK) 编译 pcre-8.37 静态库
    (OK) 完整编译android 4.4源码—问题—CSSValueKeywords.cpp—CSSPropertyNames.cpp
    (OK) 调试cBPM—CentOS7—gdb—gdbserver—问题的解决—完整的调试过程—成功
    OK) 调试cBPM—CentOS7—gdb—gdbserver—问题的解决—5—process指向错误地址
    (OK) 调试cBPM—CentOS7—gdb—gdbserver—问题的解决—4—段错误
    (OK) 调试cBPM—CentOS7—gdb—gdbserver—问题的解决—3—段错误
    (OK) 编译cBPM-android—CentOS 7—NDK8—androideabi-4.7—API14—3版
  • 原文地址:https://www.cnblogs.com/liubin0509/p/2373797.html
Copyright © 2011-2022 走看看