zoukankan      html  css  js  c++  java
  • javassist AOP

    对于AOP,这个概念,不用解释,主要用途很多,我这里主要是为了后续研究如何实现APM做准备。前面研究了动态代理实现AOP,考虑到性能的问题,改用javassist直接修改直接码实现!

    javassist的使用,可以参考官网, 在用eclipse开发程序的时候,要将这个javassist的jar包放入classpath下。若基于maven开发的话,也有对应的maven插件,很简单的事情!

    下面主要列举一下常用的类以及方法:

    1 获取JVM中已经加载的所有的类的集合,即pool
    2 ClassPool pool = ClassPool.getDefault(); 
    3 
    4 获取指定类名对应的类
    5 CtClass cc = pool.get("带有包名的全路径类名");
    6 
    7 为这个类设置超级类
    8 cc.setSuperclass(pool.get("指定带有全路径的类名"));

    另外还有CtMethod,CtField等等,这些可以到官网找相关的API文档了解其使用方法。下面通过一个简单的例子看看如何使用javassist来动态编写程序,实现AOP。

    先定义一个业务类Feed.java,其中的函数,就好比是我们业务系统中的某个操作。

     1 package javassit_aop;
     2 
     3 /**
     4  * 
     5  * @author  shihuc
     6  * @date    Mar 24, 2016
     7  *
     8  */
     9 public class Feed {
    10   public void forTest(){
    11     System.out.println("----------execute function "forTest()"-----------");
    12   }
    13 }

    接下来,定义一个测试类,在这个测试类里面,通过javassist的函数调用,实现切面织入,也就是AOP的目的所在。这个类TEST.java:

     1 package javassit_aop;
     2 
     3 import javassist.CannotCompileException;
     4 import javassist.ClassPool;
     5 import javassist.CtClass;
     6 import javassist.CtMethod;
     7 import javassist.CtNewMethod;
     8 import javassist.NotFoundException;
     9 
    10 /**
    11  * 
    12  * @author  shihuc
    13  * @date    Mar 24, 2016
    14  *
    15  */
    16 public class TEST {
    17    public static void main(String[] args) throws NotFoundException, CannotCompileException, InstantiationException, IllegalAccessException{
    18        CtClass ctClass=ClassPool.getDefault().get("javassit_aop.Feed");
    19        String oldName="forTest";
    20        CtMethod ctMethod=ctClass.getDeclaredMethod(oldName);
    21        String newName=oldName+"$NewImpl";
    22        ctMethod.setName(newName);
    23        CtMethod newMethod=CtNewMethod.copy(ctMethod, "forTest", ctClass, null);
    24        StringBuffer sb=new StringBuffer();
    25        
    26        /*
    27         * Here, below StringBuffer is to create the new method body, what you read is the source code, 
    28         * but, it will be translated to byte code which can be interpreted by JVM.
    29         * 
    30         * To some extent, ".append(newName+"($$);
    ")" can be said as function call to the business function Feed.forTest()
    31         */
    32        sb.append("{System.out.println("Here you can do BEFORE operation");
    ")
    33          .append(newName+"($$);
    ") 
    34          .append("System.out.println("Here you can do AFTER operation");
    }");
    35        newMethod.setBody(sb.toString());  
    36        /*
    37         * Add new method 
    38         */
    39        ctClass.addMethod(newMethod);  
    40        /*
    41         * Class changed, ATTENTION, do not use "A a = new A();" to make a new instance,
    42         * because in the same classloader it do not allow to load one class more than once.
    43         */  
    44        Feed a=(Feed)ctClass.toClass().newInstance();  
    45        a.forTest();
    46    }
    47 }

    上面的代码执行完后,可以看到下面的结果:

    1 Here you can do BEFORE operation
    2 ----------execute function "forTest()"-----------
    3 Here you can do AFTER operation

    上述代码中$$表示所有的参数,关于javassist的函数调用中参数传递,可以参考官网的说明,这里截取一部分,可以先有个概念,这个和shell脚本中的function调用是参数传递非常像!

    The String object passed to the methods insertBefore(), insertAfter(), addCatch(), and insertAt() are compiled by the compiler included in Javassist. Since the compiler supports language extensions, several identifiers starting with $ have special meaning:
    
        $0, $1, $2, ...         this and actual parameters
        $args     An array of parameters. The type of $args is Object[].
        $$     All actual parameters.
        For example, m($$) is equivalent to m($1,$2,...)
         
        $cflow(...)     cflow variable
        $r     The result type. It is used in a cast expression.
        $w     The wrapper type. It is used in a cast expression.
        $_     The resulting value
        $sig     An array of java.lang.Class objects representing the formal parameter types.
        $type     A java.lang.Class object representing the formal result type.
        $class     A java.lang.Class object representing the class currently edited.

     

    虽然javassist的使用中也涉及到了反射的使用,大家都应该意识到,在产品级的软件中,若大量使用反射,性能是不会好的,当然javassist的官方组织也知道这点,所以,在使用的时候,可以通过定义interface,然后在javassist中动态编程来实现这个接口中的方法,调用方,通过这个接口来调用方法,这样就可以绕开因为反射造成的性能损失。

    另外,javassist的深入灵活的使用,后续再继续研究,并及时更新博客!

  • 相关阅读:
    Fork/Join框架基本使用
    服务端高并发分布式架构演进之路
    Netty专题(一)-----计算机网络、TCP/ICP、linux网络I/O模型
    Nginx专题(四)-----https、nginx高可用
    Nginx专题(三)-----核心原理、跨域解决、防盗链、缓存以及压缩
    微信开放平台开发第三方授权登陆(四):微信小程序
    微信开放平台开发第三方授权登陆(三):微信公众号
    微信开放平台开发第三方授权登陆(二):PC网页端
    微信开放平台开发第三方授权登陆(一)-----开发前准备
    Mysql:如果数据存在则更新,不存在则插入
  • 原文地址:https://www.cnblogs.com/shihuc/p/5316173.html
Copyright © 2011-2022 走看看