基础部份:

修改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异常时,就考虑添加上去即可

实现部份:

 public class TestJavassist {
public interface TestObject {
public void a(int a, String b); public void setAge(int value); public int getAge();
} public static void main(String[] args) throws Exception {
String proxyClassName = TestObject.class.getCanonicalName() + "$$$$";
ClassPool classPool = ClassPool.getDefault();
CtClass ctClass = classPool.makeClass(proxyClassName); // 设置接口
CtClass[] interfaces = new CtClass[1];
interfaces[0] = classPool.get(TestObject.class.getName());
ctClass.setInterfaces(interfaces); // 添加字段
CtField ctField = new CtField(classPool.get(int.class.getName()), "age", ctClass);
// 设置field属性
ctField.setModifiers(Modifier.PRIVATE);
ctClass.addField(ctField); // 添加 age getter'setter方法
String setbody = "{this.age = $1;}";
String getbody = "{return this.age;}";
for (Method method : TestObject.class.getDeclaredMethods()) {
String body = null;
switch (method.getName()) {
case "setAge":
body = setbody;
break;
case "getAge":
body = getbody;
break;
case "a":
body = "{System.out.println($1);System.out.println($2);}";
break;
default:
continue;
} Class<?> returnType = method.getReturnType();
// 转换参数CtClass
CtClass[] parameterCtClass = new CtClass[method.getParameterTypes().length];
for (int i = 0; i < method.getParameterTypes().length; i++) {
parameterCtClass[i] = classPool.get(method.getParameterTypes()[i].getName());
}
CtMethod ctMethod = new CtMethod(classPool.get(returnType.getName()), method.getName(), parameterCtClass, ctClass);
ctMethod.setModifiers(method.getModifiers());
ctMethod.setBody(body);
ctClass.addMethod(ctMethod); }
// 添加构造
ctClass.addConstructor(CtNewConstructor.defaultConstructor(ctClass)); Class<?> clz = ctClass.toClass();
TestObject obj = (TestObject) clz.newInstance();
obj.setAge(30);
System.out.println("age : " + obj.getAge());
obj.a(111, "bbb"); // ctClass.writeFile("f:/test.class");
}
}

源码讲解

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

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

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

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

5.可添加构造方法

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

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

 public static void testJavassist() throws Exception {
String proxyClassName = UserService.class.getCanonicalName() + "$$$$"; ClassPool classPool = ClassPool.getDefault();
CtClass ctClass = classPool.makeClass(proxyClassName); // 设置接口
CtClass[] interfaces = new CtClass[1];
interfaces[0] = classPool.get(UserService.class.getName());
ctClass.setInterfaces(interfaces); // 添加 方法
for (Method method : UserService.class.getDeclaredMethods()) {
String body = null;
switch (method.getName()) {
case "getName":
body = "{return $1 + \"\";}";
break;
case "getAge":
body = "{return ($w)$1;}";
break;
default:
continue;
} Class<?> returnType = method.getReturnType();
// 转换参数CtClass
CtClass[] parameterCtClass = new CtClass[method.getParameterTypes().length];
for (int i = 0; i < method.getParameterTypes().length; i++) {
parameterCtClass[i] = classPool.get(method.getParameterTypes()[i].getName());
}
CtMethod ctMethod = new CtMethod(classPool.get(returnType.getName()), method.getName(), parameterCtClass, ctClass);
ctMethod.setModifiers(method.getModifiers());
ctMethod.setBody(body);
ctClass.addMethod(ctMethod); }
// 添加构造
ctClass.addConstructor(CtNewConstructor.defaultConstructor(ctClass));
Class<?> clz = ctClass.toClass();
UserService proxy = (UserService) clz.newInstance();
run("javassist", proxy);
}
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

[编织消息框架][JAVA核心技术]动态代理应用5-javassist的更多相关文章

  1. [编织消息框架][JAVA核心技术]动态代理介绍

    由于java是种强类型静态语言,在执行时无法动态生成代码,静态语言基本都有这特性 动态生成代码有几种好处,也是弱类型语言的优点 1.部份逻辑可以实现热更新 2.远程调用实现非常适合 3.能动态生成扩展 ...

  2. [编织消息框架][JAVA核心技术]动态代理应用12-总结

    动态代理这篇比较长,是框架组成的重要基础 回顾下学到的应用技术 1.异常应用 2.annotation技术 3.数值与逻辑分享 4.jdk.cglib.javassist等动态代理技术 5.懒处理.预 ...

  3. [编织消息框架][JAVA核心技术]动态代理应用4

    基础部份: 接下来讲编译JAVA时,生成自定义class 我们用 javax.annotation.processing.AbstractProcessor 来处理 public abstract c ...

  4. [编织消息框架][JAVA核心技术]动态代理应用8-IRpcReceive实现

    private static Map<Short, Map<Byte, Method>> RECEIVE_METHOD_INFO = new HashMap<>() ...

  5. [编织消息框架][JAVA核心技术]动态代理应用7-IRpcSend实现

    根据设计生成两个接口,IRpcSend send方法返回数据要求包装成QResult对象 public interface IRpcSend { public <T> QResult< ...

  6. [编织消息框架][JAVA核心技术]动态代理应用4-annotationProcessor

    基础部份: 接下来讲编译JAVA时,生成自定义class 我们用 javax.annotation.processing.AbstractProcessor 来处理 public abstract c ...

  7. [编织消息框架][JAVA核心技术]动态代理应用2

    接下来如何实现 第一步:先把服务类,调用方法转换成数字,方便传输 第二步:提取元信息,提取又有三种方式,三种各有优点,最优方式是第一种 1.编译java时处理 2.程序启动时处理,预处理 3.调用时处 ...

  8. [编织消息框架][JAVA核心技术]动态代理应用9-扫描class

    之前介绍的annotationProcessor能在编译时生成自定义class,但有个缺点,只能每次添加/删除java文件才会执行,那天换了个人不清楚就坑大了 还记得之前介绍的编译时处理,懒处理,还有 ...

  9. [编织消息框架][JAVA核心技术]动态代理应用10-水平扩展方案

    服务分为系统服务同用户服务两种 水平扩展是基于系统服务,而拆分方式又有几种方案,按数据跟业务情况来做决策 1.每个服务独立存储(图1):每个服务只负责一个或多个领域实体存储,A服务不能直接修改B服务的 ...

随机推荐

  1. Linux系统(四)负载均衡LVS集群之NAT模式

    序言 提到LVS,就从章文嵩博士开始吧,反正也不知道如何下笔来写这一篇.章大博士,读博时候创建这个lvs软件项目,但是他提倡开源精神,在用户的建议和反馈中,这个花了他两周时间开发的开源软件不断得到改建 ...

  2. 从零开始--Spring项目整合(2)整合SpringMVC

    1.pom.xml 定义版本 <properties> <spring.version>4.2.7.RELEASE</spring.version> <jac ...

  3. 旺财速啃H5框架之Bootstrap(六)

    年后太忙,一直没有更新 好,这篇结束,速啃嘛,就应该拿重点,实用点.继续之前的内容,接着来讲讲网页中常用的布局组件与插件,我喜欢用简单的直接的话或案例来说明,就是针对那些想快速能做出点东西的人而准备的 ...

  4. python excel操作总结

    1.openpyxl包的导入 Dos命令行输入 pip install openpyxl==2.3.3 这里注意一下openpyxl包的版本问题 版本装的太高有很多api不支持了,所以笔者这里用的是2 ...

  5. 1755: [Usaco2005 qua]Bank Interest

    1755: [Usaco2005 qua]Bank Interest Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 187  Solved: 162[Su ...

  6. 用php+mysql+ajax+jquery做省市区三级联动

    要求:写一个省市区(或者年月日)的三级联动,实现地区或时间的下拉选择. 实现技术:php ajax 实现:省级下拉变化时市下拉区下拉跟着变化,市级下拉变化时区下拉跟着变化. 使用chinastates ...

  7. js实现ajax的post请求步骤

    post请求步骤与前篇的get请求步骤差别不大,只是增加了 xhr.setRequestHeader("Content-type","application/x-www- ...

  8. SEO-搜索引擎高级搜索指令

    搜索引擎高级搜索指令 1.双引号 把搜索词放在双引号中,代表完全匹配搜索,也就是说搜索结果返回的页面包含双引号中出现的所有的词,连顺序也必须完全匹配.bd和Google 都支持这个指令.例如搜索: & ...

  9. ABP入门系列(14)——应用BootstrapTable表格插件

    ABP入门系列目录--学习Abp框架之实操演练 源码路径:Github-LearningMpaAbp 1. 引言 之前的文章ABP入门系列(7)--分页实现讲解了如何进行分页展示,但其分页展示仅适用于 ...

  10. Git-最简单的本地项目变成版本仓库,然后把内容推送到GitHub仓库

    (注:本文的前提是本地Git仓库和github仓库之间已经存在SSH key了,所以如果没有建立联系的小伙伴们请先建立联系) 具体操作: 一:把本地项目变成版本仓库 1.把本地的一个项目目录编程版本库 ...