zoukankan      html  css  js  c++  java
  • [编织消息框架][JAVA核心技术]动态代理应用5-javassist

    基础部份:

    修改class我们用到javassist,在pom.xml添加

    <properties>
        <javassist.version>3.18.2-GA</javassist.version>
    </properties>        
    <dependency>
        <groupId>org.javassist</groupId>
        <artifactId>javassist</artifactId>
        <version>${javassist.version}</version>
    </dependency> 

    1.ClassPool 负责加载CtClass,其中可添加ClassPath,优先级从父ClassPath加载
    2.CtClass 处理class信息 从ClassPool make
    3.CtField 处理field信息
    4.CtMethod 处理method信息
    5.CtConstructor 处理constructor信息

    ClassPool 源码浅读:

    AccessController.doPrivileged 方法能够使一段受信任代码获得更大的权限,甚至比调用它的应用程序还要多,可做到临时访问更多的资源,

    由于技术内容跟本书无太大关系,我们只关心当抛出java.security.AccessControlException异常时,就考虑添加上去即可

    实现部份:

     1 public class TestJavassist {
     2     public interface TestObject {
     3     public void a(int a, String b);
     4 
     5     public void setAge(int value);
     6 
     7     public int getAge();
     8     }
     9 
    10     public static void main(String[] args) throws Exception {
    11         String proxyClassName = TestObject.class.getCanonicalName() + "$$$$";
    12         ClassPool classPool = ClassPool.getDefault();
    13         CtClass ctClass = classPool.makeClass(proxyClassName);
    14 
    15         // 设置接口
    16         CtClass[] interfaces = new CtClass[1];
    17         interfaces[0] = classPool.get(TestObject.class.getName());
    18         ctClass.setInterfaces(interfaces);
    19 
    20         // 添加字段
    21         CtField ctField = new CtField(classPool.get(int.class.getName()), "age", ctClass);
    22         // 设置field属性
    23         ctField.setModifiers(Modifier.PRIVATE);
    24         ctClass.addField(ctField);
    25 
    26         // 添加 age getter'setter方法
    27         String setbody = "{this.age = $1;}";
    28         String getbody = "{return this.age;}";
    29         for (Method method : TestObject.class.getDeclaredMethods()) {
    30             String body = null;
    31             switch (method.getName()) {
    32                 case "setAge":
    33                     body = setbody;
    34                 break;
    35                 case "getAge":
    36                     body = getbody;
    37                 break;
    38                 case "a":
    39                     body = "{System.out.println($1);System.out.println($2);}";
    40                 break;
    41                 default:
    42                     continue;
    43             }
    44 
    45             Class<?> returnType = method.getReturnType();
    46             // 转换参数CtClass
    47             CtClass[] parameterCtClass = new CtClass[method.getParameterTypes().length];
    48             for (int i = 0; i < method.getParameterTypes().length; i++) {
    49                 parameterCtClass[i] = classPool.get(method.getParameterTypes()[i].getName());
    50             }
    51             CtMethod ctMethod = new CtMethod(classPool.get(returnType.getName()), method.getName(), parameterCtClass, ctClass);
    52             ctMethod.setModifiers(method.getModifiers());
    53             ctMethod.setBody(body);
    54             ctClass.addMethod(ctMethod);
    55 
    56         }
    57         // 添加构造
    58         ctClass.addConstructor(CtNewConstructor.defaultConstructor(ctClass));
    59 
    60         Class<?> clz = ctClass.toClass();
    61         TestObject obj = (TestObject) clz.newInstance();
    62         obj.setAge(30);
    63         System.out.println("age : " + obj.getAge());
    64         obj.a(111, "bbb");
    65 
    66         // ctClass.writeFile("f:/test.class");
    67     }
    68 }

    源码讲解

    1.先通过classPool.makeClass 创建新的类,名称是原来类+自定义标记

    2.所有的java类型必须转换成CtClass

    3.要给创建的自定义类CtClass 添加接口类或继承父类,保留原类型

    4.创建方法时特别注意处理java类型 

    5.可添加构造方法

    下面给出常用的参数对照表,注意:在不同域使用不同有的少点,不过都大同小异

     接着在之前的TestProxy 测试添加 testJavassist 看下执行效率,速度与native相差不大,原因是生成的指令很少,感兴趣的话通过 ctClass.writeFile()保存class 然后再用javap查看生成指令数

     1 public static void testJavassist() throws Exception {
     2     String proxyClassName = UserService.class.getCanonicalName() + "$$$$";
     3 
     4     ClassPool classPool = ClassPool.getDefault();
     5     CtClass ctClass = classPool.makeClass(proxyClassName);
     6 
     7     // 设置接口
     8     CtClass[] interfaces = new CtClass[1];
     9     interfaces[0] = classPool.get(UserService.class.getName());
    10     ctClass.setInterfaces(interfaces);
    11 
    12     // 添加 方法
    13     for (Method method : UserService.class.getDeclaredMethods()) {
    14         String body = null;
    15         switch (method.getName()) {
    16         case "getName":
    17             body = "{return $1 + "";}";
    18         break;
    19         case "getAge":
    20             body = "{return ($w)$1;}";
    21         break;
    22         default:
    23             continue;
    24         }
    25 
    26         Class<?> returnType = method.getReturnType();
    27         // 转换参数CtClass
    28         CtClass[] parameterCtClass = new CtClass[method.getParameterTypes().length];
    29         for (int i = 0; i < method.getParameterTypes().length; i++) {
    30             parameterCtClass[i] = classPool.get(method.getParameterTypes()[i].getName());
    31         }
    32         CtMethod ctMethod = new CtMethod(classPool.get(returnType.getName()), method.getName(), parameterCtClass, ctClass);
    33         ctMethod.setModifiers(method.getModifiers());
    34         ctMethod.setBody(body);
    35         ctClass.addMethod(ctMethod);
    36 
    37     }
    38     // 添加构造
    39     ctClass.addConstructor(CtNewConstructor.defaultConstructor(ctClass));
    40     Class<?> clz = ctClass.toClass();
    41     UserService proxy = (UserService) clz.newInstance();
    42     run("javassist", proxy);
    43 }
    native: 177 native: 183 native: 128 native: 171 native: 127 native: 141 native: 184 native: 126 native: 127 native: 127 native: 127 native: 126 native: 127 native: 126 native: 127
    jdk: 214 jdk: 169 jdk: 169 jdk: 169 jdk: 169 jdk: 169 jdk: 170 jdk: 169 jdk: 170 jdk: 169 jdk: 169 jdk: 171 jdk: 170 jdk: 169 jdk: 170
    javassist: 146 javassist: 139 javassist: 140 javassist: 140 javassist: 140 javassist: 139 javassist: 140 javassist: 140 javassist: 138 javassist: 140 javassist: 140 javassist: 141 javassist: 139 javassist: 139 javassist: 139

    资料来源 :http://jboss-javassist.github.io/javassist/tutorial/tutorial2.html#runtime

    http://wsmajunfeng.iteye.com/blog/1912983

  • 相关阅读:
    淘宝首页广告圆角切换标签未解之谜(vml)
    chrome的google官方在线安装太坑爹了,找到一个离线下载地址
    kejun写的响应性设计和开发
    HTTP状态码
    xwebkitspeech 语音输入功能
    Avoid Redirects 避免重定向
    webstorm下使用github
    开通了github,用webstorm上传,敲命令行太累。
    jQuery1.6.1下event鼠标事件有BUG,升级到1.7.1可以解决问题。
    从程序员到项目经理(五):不是人人都懂的学习要点
  • 原文地址:https://www.cnblogs.com/solq111/p/6672527.html
Copyright © 2011-2022 走看看