/**
* 创建新对象
*
* @throws NotFoundException
* @throws CannotCompileException
* @throws IOException
*/
static void addNewClass() throws NotFoundException, CannotCompileException, IOException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
//使用单例模式
ClassPool classPool = ClassPool.getDefault();
//创建对象
CtClass ctClass = classPool.makeClass("com.sb.javassists.CreateObject");
//添加属性
CtField id = new CtField(classPool.get("java.lang.Integer"), "id", ctClass);
id.setModifiers(Modifier.PRIVATE);
ctClass.addField(id);
//添加属性
CtField name = new CtField(classPool.get("java.lang.String"), "name", ctClass);
name.setModifiers(Modifier.PRIVATE);
ctClass.addField(name);
//添加属性(直接写java代码)
CtField desc = CtField.make("private String desc;", ctClass);
ctClass.addField(desc);
//无惨构造函数
CtConstructor ctConstructor = new CtConstructor(new CtClass[]{}, ctClass);
ctConstructor.setBody("{}");
//设置构造函数访问权限
ctConstructor.setModifiers(Modifier.PRIVATE);
ctClass.addConstructor(ctConstructor);
// 无参构造函数添加
// ctClass.addConstructor(CtNewConstructor.defaultConstructor(ctClass));
//2个参数构造函数
ctConstructor = new CtConstructor(new CtClass[]{classPool.get("java.lang.Integer"), classPool.get("java.lang" +
".String")}, ctClass);
//构造函数函数体
ctConstructor.setBody("{$0.id=$1;this.name = $2;}");
ctConstructor.setModifiers(Modifier.PROTECTED);
ctClass.addConstructor(ctConstructor);
//3个参构造函数
ctConstructor = new CtConstructor(new CtClass[]{classPool.get("java.lang.Integer"), classPool.get("java.lang" +
".String"), classPool.get("java.lang.String")}, ctClass);
//构造函数函数体,$0是一个特殊参数即this变量
ctConstructor.setBody("{$0.id = $1;$0.name = $2;$0.desc = $3;}");
//默认构造函数为public
ctClass.addConstructor(ctConstructor);
// set get 方法
ctClass.addMethod(CtNewMethod.setter("setId", id));
ctClass.addMethod(CtNewMethod.getter("getId", id));
ctClass.addMethod(CtNewMethod.setter("setName", name));
ctClass.addMethod(CtNewMethod.getter("getName", name));
ctClass.addMethod(CtNewMethod.setter("setDesc", desc));
ctClass.addMethod(CtNewMethod.getter("getDesc", desc));
//添加方法
CtMethod printInfo = new CtMethod(CtClass.voidType, "printInfo", new CtClass[]{}, ctClass);
printInfo.setModifiers(Modifier.PUBLIC);
printInfo.setBody("{System.out.println(\"id:\"+$0.id +\" name:\"+this.name+\" desc:\"+this.desc);}");
ctClass.addMethod(printInfo);
//添加方法(直接写"java代码")
CtMethod doDescInfo = CtNewMethod.make("private void doDescInfo() { System.out.println(\"my " +
"desc:\"+$0.desc);" +
" " +
"}", ctClass);
ctClass.addMethod(doDescInfo);
//方法中调用方法
CtMethod descInfo = CtNewMethod.make("public void descInfo () { $proceed(); }", ctClass, "this", "doDescInfo");
ctClass.addMethod(descInfo);
//加载字节码文件生成Class对象、对象获取
Class classObject = ctClass.toClass();
//构造函数创建对象
Constructor constructor = classObject.getDeclaredConstructor(new Class[]{Integer.class, String.class});
Object object = constructor.newInstance(18, "javassist name");
//反射获取方法对象
Method setDescMethod = object.getClass().getMethod("setDesc", String.class);
setDescMethod.invoke(object, "javassist desc");
Method printInfoInvoke = classObject.getMethod("printInfo");
printInfoInvoke.invoke(object, new Object[]{});
Method descInfoInvoke = classObject.getMethod(("descInfo"), new Class[]{});
descInfoInvoke.invoke(object, new Object[]{});
ctClass.writeFile("/Users/wanghaidong/Documents/workspace/projects/ownProjects/inter-sbl/springboot-socks" +
"/all");
ctClass.toBytecode();
}
2、生成字节码文件反编译
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.sb.javassists;
public class CreateObject {
private Integer id;
private String name;
private String desc;
private CreateObject() {
}
protected CreateObject(Integer var1, String var2) {
this.id = var1;
this.name = var2;
}
public CreateObject(Integer var1, String var2, String var3) {
this.id = var1;
this.name = var2;
this.desc = var3;
}
public void setId(Integer var1) {
this.id = var1;
}
public Integer getId() {
return this.id;
}
public void setName(String var1) {
this.name = var1;
}
public String getName() {
return this.name;
}
public void setDesc(String var1) {
this.desc = var1;
}
public String getDesc() {
return this.desc;
}
public void printInfo() {
System.out.println("id:" + this.id + " name:" + this.name + " desc:" + this.desc);
}
private void doDescInfo() {
System.out.println("my desc:" + this.desc);
}
public void descInfo() {
this.doDescInfo();
Object var10000 = null;
}
}
public class UpdateObject {
public void update() {
System.out.println("execute update object update method");
}
}
2、已有类加载并执行
/**
* 加载已指定类
*
* @throws NotFoundException
* @throws CannotCompileException
* @throws IllegalAccessException
* @throws InstantiationException
*/
static void loadClassByPath() throws NotFoundException, CannotCompileException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
ClassPool classPool = ClassPool.getDefault();
String path = "com.sb.javassists.UpdateObject";
CtClass ctClass = classPool.get(path);
Class classObject = ctClass.toClass();
Object object = classObject.newInstance();
Method method = classObject.getDeclaredMethod("update");
method.invoke(object, new Object[]{});
}
3、加载原有字节码文件并一次修改多行
/**
* 多行代码添加使用{}
*
* @throws NotFoundException
* @throws CannotCompileException
*/
static void updateMethodMore() throws NotFoundException, CannotCompileException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, IOException {
ClassPool classPool = ClassPool.getDefault();
String path = "com.sb.javassists.UpdateObject";
CtClass ctClass = classPool.get(path);
CtMethod ctMethod = ctClass.getDeclaredMethod("update");
//注意这样添加的每一行代码其作用范围都是在本代码快而不是方法,所以如果在代码块之外引用则会报未定义变量异常
ctMethod.insertBefore("long begin= System.currentTimeMillis();");
ctMethod.insertAfter("{long end = System.currentTimeMillis();System.out.println(end);}");
Class classObject = ctClass.toClass();
Object object = classObject.newInstance();
Method method = classObject.getDeclaredMethod("update");
method.invoke(object, new Object[]{});
//将修改后的字节码写入文件生成.class 文件
ctClass.writeFile("/Users/wanghaidong/Documents/workspace/projects/ownProjects/inter-sbl/springboot-socks" +
"/all");
}
(2)、修改后.class 文件
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.sb.javassists;
public class UpdateObject {
public UpdateObject() {
}
public void update() {
long var1 = System.currentTimeMillis();
System.out.println("execute update object update method");
Object var4 = null;
long var5 = System.currentTimeMillis();
System.out.println(var5);
}
}
5、加载原有字节码文件并添加异常捕获
/**
* 方法添加异常try(){}catch(){}
* 注意添加异常块时一定要添加throw $e即一定要抛出异常,否则编译错误;$e:标识异常值
* javassist.CannotCompileException: by javassist.bytecode.BadBytecode: no basic block at 9
*
* @throws NotFoundException
* @throws CannotCompileException
* @throws IllegalAccessException
* @throws InstantiationException
*/
static void addTryCatch() throws NotFoundException, CannotCompileException, IllegalAccessException, InstantiationException, IOException, NoSuchMethodException, InvocationTargetException {
ClassPool classPool = ClassPool.getDefault();
String path = "com.sb.javassists.UpdateObject";
CtClass ctClass = classPool.get(path);
CtMethod ctMethod = ctClass.getDeclaredMethod("update");
//异常Exception类引用
CtClass exception = ClassPool.getDefault().get("java.lang.Exception");
//添加异常捕获;打印异常并再次抛出异常,$e代表异常值
ctMethod.addCatch("{ System.out.println($e); throw $e; }", exception);
//这种写法是可以的
// ctMethod.addCatch("{throw $e; }", exception);
//这种写法报异常,编译无法通过
// ctMethod.addCatch("{System.out.println($e);}", exception);
Class classObject = ctClass.toClass();
Object object = classObject.newInstance();
Method method = classObject.getDeclaredMethod("update");
method.invoke(object, new Object[]{});
ctClass.writeFile("/Users/wanghaidong/Documents/workspace/projects/ownProjects/inter-sbl/springboot-socks" +
"/all");
}
(2)、修改后.class 文件
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.sb.javassists;
public class UpdateObject {
public UpdateObject() {
}
public void update() {
try {
System.out.println("execute update object update method");
} catch (Exception var2) {
System.out.println(var2);
throw var2;
}
}
}
6、加载原有字节码文件并添加新方法、新方法调用原有方法、间接实现方法体修改
/**
* 修改方法
*
* @throws NotFoundException
* @throws CannotCompileException
* @throws IOException
* @throws IllegalAccessException
* @throws InstantiationException
* @throws NoSuchMethodException
* @throws InvocationTargetException
*/
static void addTryCatchFinally() throws NotFoundException, CannotCompileException, IOException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
ClassPool classPool = ClassPool.getDefault();
String path = "com.sb.javassists.UpdateObject";
CtClass ctClass = classPool.get(path);
String methodName = "update";
String methodNameNew = "doUpdate";
CtMethod ctMethod = ctClass.getDeclaredMethod(methodName);
//修改原方法名称()
ctMethod.setName(methodNameNew);
//原方法拷贝,只拷贝了方法结构即方法返回类型、形参,未拷贝方法名称、方法体;
CtMethod newCtMethod = CtNewMethod.copy(ctMethod, methodName, ctClass, null);
//方法体添加
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("{try{");
//调用原有方法,($$)标识方法所有参数,相当与this.doUpdate($1,$2,$3……)
stringBuffer.append(methodNameNew).append("($$);");
//为了测试在这里添加异常
stringBuffer.append("throw new Exception(\"test exception\");");
//这里使用手写添加异常所以$e在这里无法识别
stringBuffer.append("}catch(Exception e){System.out.println(\"异常信息:\"+e.getMessage" +
"());}");
stringBuffer.append("finally{System.out.println(\"add tyr catch finally end \");}");
//上面这些都是一个方法块,所以不要丢了开始和结束时的{}
stringBuffer.append("}");
// 新方法设置方法体
newCtMethod.setBody(stringBuffer.toString());
//添加新方法
ctClass.addMethod(newCtMethod);
Class classObject = ctClass.toClass();
Object object = classObject.newInstance();
Method method = classObject.getDeclaredMethod("update");
method.invoke(object, new Object[]{});
ctClass.writeFile("/Users/wanghaidong/Documents/workspace/projects/ownProjects/inter-sbl/springboot-socks" +
"/all");
}
(2)、修改后.class文件
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.sb.javassists;
public class UpdateObject {
public UpdateObject() {
}
public void doUpdate() {
System.out.println("execute update object update method");
}
public void update() {
try {
this.doUpdate();
throw new Exception("test exception");
} catch (Exception var4) {
System.out.println("异常信息:" + var4.getMessage());
} finally {
System.out.println("add tyr catch finally end ");
}
}
}
7、加载原有字节码文件并添加链路id值
/**
* 添加TraceId,写全路劲
*
* @throws NotFoundException
* @throws CannotCompileException
* @throws IllegalAccessException
* @throws InstantiationException
* @throws IOException
* @throws NoSuchMethodException
* @throws InvocationTargetException
*/
static void addTraceId() throws NotFoundException, CannotCompileException,
IllegalAccessException, InstantiationException, IOException, NoSuchMethodException, InvocationTargetException {
ClassPool classPool = ClassPool.getDefault();
String path = "com.sb.javassists.UpdateObject";
CtClass ctClass = classPool.get(path);
String methodName = "update";
String methodNameNew = "doUpdate";
CtMethod ctMethod = ctClass.getDeclaredMethod("update");
//修改原方法名称
ctMethod.setName(methodNameNew);
//定义新方法,拷贝旧方法方法结构体、方法返回值、形参,未拷贝方法名称、方法体;
CtMethod newCtMethod = CtNewMethod.copy(ctMethod, methodName, ctClass, null);
//新方法方法体
StringBuffer bodyBuffer = new StringBuffer();
//设置traceId 值
bodyBuffer.append("{org.slf4j.MDC.put(\"traceId\",\"1\");try{");
// 调用原有代码,类似于method();($$)表示所有的参数
// $$是所有方法参数的简写,主要用在方法调用上。例如:
// 原方法 move(String a,String b)
// move($$) 相当于move($1,$2)
//
bodyBuffer.append(methodNameNew).append("($$);");
// 获取traceId的值
bodyBuffer.append("String traceId= org.slf4j.MDC.get(\"traceId\");System.out.println(traceId);");
bodyBuffer.append("throw new Exception(\"test exception\");");
bodyBuffer.append("}catch(Exception e){System.out.println(e.getMessage());}");
bodyBuffer.append("finally{org.slf4j.MDC.remove(\"traceId\");System.out.println(\"ok!\");}");
bodyBuffer.append("}");
// 新方法体设置
newCtMethod.setBody(bodyBuffer.toString());
//添加新方法
ctClass.addMethod(newCtMethod);
Class classObject = ctClass.toClass();
Object object = classObject.newInstance();
Method method = classObject.getDeclaredMethod("update");
method.invoke(object, new Object[]{});
ctClass.writeFile("/Users/wanghaidong/Documents/workspace/projects/ownProjects/inter-sbl/springboot-socks" +
"/all");
}
(2)、修改后.class 文件
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.sb.javassists;
import org.slf4j.MDC;
public class UpdateObject {
public UpdateObject() {
}
public void doUpdate() {
System.out.println("execute update object update method");
}
public void update() {
MDC.put("traceId", "1");
try {
this.doUpdate();
String var1 = MDC.get("traceId");
System.out.println(var1);
throw new Exception("test exception");
} catch (Exception var5) {
System.out.println(var5.getMessage());
} finally {
MDC.remove("traceId");
System.out.println("ok!");
}
}
}
8、加载原有字节码文件并添加链路id值
public class Student implements People {
@Override
public void say() {
System.out.println("HELLO JAVA HELLO DYNAMIC PROXY");
}
@Override
public void eat() {
System.out.println("input byte return Class object");
}
}
(2)、代理类生成
public Object getProxy(Class> type) throws IllegalAccessException, InstantiationException {
//代理工程
ProxyFactory f = new ProxyFactory();
//设置生成代理类的类,这里注意这里的type是类不是接口的Class对象
f.setSuperclass(type);
//创建指定类的代理类类对象
Class c = f.createClass();
//方法处理类,功能类似jdk动态代理中的InvocationHandler实现类
MyMethodHandler mi = new MyMethodHandler();
//创建代理类
Object proxy = c.newInstance();
//代理类设置处理类handler(构造函数注入、方法注入)
((Proxy) proxy).setHandler(mi);
return proxy;
}
(3)、代理关系
/**
* 处理类,这个类类似于jdk的InvocationHandler、起到代理类、被代理类关联关系
*/
private static class MyMethodHandler implements MethodHandler {
/**
* @param target 目标类
* @param method 代理类调用方法
* @param method1 动态生成的方法
* @param methodParams 代理类调用方法参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object target, Method method, Method method1, Object[] methodParams) throws Throwable {
for (Object object : methodParams) {
System.out.println(object.getClass().getName());
}
System.out.println("method name =" + method.getName());
System.out.println("method1 name =" + method1.getName());
System.out.println("method execute before");
Object res = method1.invoke(target, methodParams);
System.out.println("method execute after");
return res;
}
}
(4)、执行结果
method name =say
method1 name =_d8say
method execute before
HELLO JAVA HELLO DYNAMIC PROXY
method execute after
2、使用javassist bytecode 生成代理类
public class Student implements People {
@Override
public void say() {
System.out.println("HELLO JAVA HELLO DYNAMIC PROXY");
}
@Override
public void eat() {
System.out.println("input byte return Class object");
}
}
(2)、调用类
// 使用javassist 来动态生成代理类
Student student = new Student();
JavassistProxyFactory javassistProxyFactory = new JavassistProxyFactory();
People proxy = javassistProxyFactory.getProxy(Student.class, new MyInvocationHandler(student));
proxy.say();
(3)、生成代理类工厂
import java.lang.reflect.InvocationHandler;
public class JavassistProxyFactory implements ProxyFactory {
@Override
public T getProxy(Class target, InvocationHandler handler) throws Throwable {
return (T) ProxyGenerator.newProxyInstance(Thread.currentThread().getContextClassLoader(),
target, handler);
}
}
(4)、工厂接口
import java.lang.reflect.InvocationHandler;
public interface ProxyFactory {
/**
* 泛型方法
*
* @param target
* @param handler
* @param
* @return
* @throws Throwable
*/
T getProxy(Class target, InvocationHandler handler) throws Throwable;
}
(5)、使用javassist byteCode 生成代理类
import javassist.*;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/***
* @author wanghaidong
* @data 2019/8/23
*/
public class ProxyGenerator {
private static final AtomicInteger counter = new AtomicInteger(1);
/**
* 缓存
*/
private static final ConcurrentHashMap, Object> proxyInstanceCache = new ConcurrentHashMap<>();
/**
* 代理类对象生成
*
* @param classLoader 类加载器
* @param targetClass 被代理类(委托类),这个参数可以按照自己需求传递两种参数
* 第一种:被代理类,通过他可以获取代理类名称、接口方法;第二种:直接传接口class对象集合
* @param invocationHandler 调用处理器,做为代理关系存在
* @return
* @throws Exception
*/
public static Object newProxyInstance(ClassLoader classLoader, Class> targetClass, InvocationHandler invocationHandler)
throws Exception {
//判断是否在缓存中
if (proxyInstanceCache.containsKey(targetClass)) {
return proxyInstanceCache.get(targetClass);
}
//生成类容器
ClassPool pool = ClassPool.getDefault();
//生成代理类的全限定名
String qualifiedName = generateClassName(targetClass);
CtClass proxy = pool.makeClass(qualifiedName);
//添加属性,接口方法列表
CtField mf = CtField.make("public static java.lang.reflect.Method[] methods;", proxy);
proxy.addField(mf);
//添加InvocationHandler变量
CtField hf = CtField.make("private " + InvocationHandler.class.getName() + " handler;", proxy);
proxy.addField(hf);
//生成构造函数,参数为InvocationHandler 类型并给定义的handler 变量赋值
CtConstructor constructor = new CtConstructor(new CtClass[]{pool.get(InvocationHandler.class.getName())}, proxy);
constructor.setBody("this.handler=$1;");
constructor.setModifiers(Modifier.PUBLIC);
proxy.addConstructor(constructor);
//无参构造函数添加
proxy.addConstructor(CtNewConstructor.defaultConstructor(proxy));
//获取被代理类的所有接口类类型对象
Class>[] classes = targetClass.getInterfaces();
List> interfaces = Arrays.asList(classes);
//遍历所有接口
List methods = new ArrayList<>();
for (Class cls : interfaces) {
CtClass ctClass = pool.get(cls.getName());
//给代理类添加实现接口
proxy.addInterface(ctClass);
//获取接口所有方法
Method[] arr = cls.getDeclaredMethods();
//遍历方法并
for (Method method : arr) {
int ix = methods.size();
//方法返回值类型
Class> rt = method.getReturnType();
//方法参数类型
Class>[] pts = method.getParameterTypes();
StringBuilder code = new StringBuilder("Object[] args = new Object[").append(pts.length).append("];");
for (int j = 0; j < pts.length; j++) {
code.append(" args[").append(j).append("] = ($w)$").append(j + 1).append(";");
}
code.append(" Object ret = handler.invoke(this, methods[" + ix + "], args);");
if (!Void.TYPE.equals(rt)) {
code.append(" return ").append(asArgument(rt, "ret")).append(";");
}
StringBuilder sb = new StringBuilder(1024);
sb.append(modifier(method.getModifiers())).append(' ').append(getParameterType(rt)).append(' ').append(method.getName());
sb.append('(');
for (int i = 0; i < pts.length; i++) {
if (i > 0) {
sb.append(',');
}
sb.append(getParameterType(pts[i]));
sb.append(" arg").append(i);
}
sb.append(')');
//方法抛出异常
Class>[] ets = method.getExceptionTypes();
if (ets != null && ets.length > 0) {
sb.append(" throws ");
for (int i = 0; i < ets.length; i++) {
if (i > 0) {
sb.append(',');
}
sb.append(getParameterType(ets[i]));
}
}
sb.append('{').append(code.toString()).append('}');
CtMethod ctMethod = CtMethod.make(sb.toString(), proxy);
proxy.addMethod(ctMethod);
methods.add(method);
}
}
//代理类访问权限设置
proxy.setModifiers(Modifier.PUBLIC);
//加载字节码文件生成Class对象、对象获取
Class> proxyClass = proxy.toClass();
proxyClass.getField("methods").set(null, methods.toArray(new Method[0]));
//获取构造函数
Object instance = proxyClass.getConstructor(InvocationHandler.class).newInstance(invocationHandler);
Object old = proxyInstanceCache.putIfAbsent(targetClass, instance);
if (old != null) {
instance = old;
}
//字节码文件保存
proxy.writeFile("/Users/wanghaidong/Documents/workspace/projects/ownProjects/inter-sbl/springboot-socks" +
"/all");
return instance;
}
/**
* 访问权限获取
*
* @param mod
* @return
*/
private static String modifier(int mod) {
if (Modifier.isPublic(mod)) {
return "public";
}
if (Modifier.isProtected(mod)) {
return "protected";
}
if (Modifier.isPrivate(mod)) {
return "private";
}
return "";
}
/**
* 数组类型返回 String[]
*
* @param c
* @return
*/
public static String getParameterType(Class> c) {
//数组类型
if (c.isArray()) {
StringBuilder sb = new StringBuilder();
do {
sb.append("[]");
c = c.getComponentType();
} while (c.isArray());
return c.getName() + sb.toString();
}
return c.getName();
}
/**
* 参数类型判断
*
* @param cl
* @param name
* @return
*/
private static String asArgument(Class> cl, String name) {
if (cl.isPrimitive()) {
if (Boolean.TYPE == cl) {
return name + "==null?false:((Boolean)" + name + ").booleanValue()";
}
if (Byte.TYPE == cl) {
return name + "==null?(byte)0:((Byte)" + name + ").byteValue()";
}
if (Character.TYPE == cl) {
return name + "==null?(char)0:((Character)" + name + ").charValue()";
}
if (Double.TYPE == cl) {
return name + "==null?(double)0:((Double)" + name + ").doubleValue()";
}
if (Float.TYPE == cl) {
return name + "==null?(float)0:((Float)" + name + ").floatValue()";
}
if (Integer.TYPE == cl) {
return name + "==null?(int)0:((Integer)" + name + ").intValue()";
}
if (Long.TYPE == cl) {
return name + "==null?(long)0:((Long)" + name + ").longValue()";
}
if (Short.TYPE == cl) {
return name + "==null?(short)0:((Short)" + name + ").shortValue()";
}
throw new RuntimeException(name + " is unknown primitive type.");
}
return "(" + getParameterType(cl) + ")" + name;
}
/**
* 生成代理类名称
*
* @param type
* @return
*/
private static String generateClassName(Class> type) {
return String.format("%s$Proxy%d", type.getName(), counter.getAndIncrement());
}
}
(6)、执行结果
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class Student$Proxy1 implements People {
public static Method[] methods;
private InvocationHandler handler;
public Student$Proxy1(InvocationHandler var1) {
this.handler = var1;
}
public Student$Proxy1() {
}
public void eat() {
Object[] var1 = new Object[0];
this.handler.invoke(this, methods[0], var1);
}
public void say() {
Object[] var1 = new Object[0];
this.handler.invoke(this, methods[1], var1);
}
}
整个过程使用javassist 按照委托类实现接口获取接口方法来动态生成代理类字节码文件,并加载该字节码文件生成Class对象……
@Override
@SuppressWarnings("unchecked")
public T getProxy(Invoker invoker, Class>[] interfaces) {
return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}
这里有个奇怪的问题,Proxy类中的newInstance 是一个抽象方法,那他是在哪里实现的,如果第一次看或比较粗心你可能也和我一样在想他到底是在哪实现的。后来发现就在眼前(哎远在天边近在眼前……),看下面代理类生成代码块,是不是想弄死自己的心都有……
// create ProxyInstance class.
String pcn = pkg + ".proxy" + id;
ccp.setClassName(pcn);
ccp.addField("public static java.lang.reflect.Method[] methods;");
ccp.addField("private " + InvocationHandler.class.getName() + " handler;");
ccp.addConstructor(Modifier.PUBLIC, new Class>[]{InvocationHandler.class}, new Class>[0], "handler=$1;");
ccp.addDefaultConstructor();
Class> clazz = ccp.toClass();
clazz.getField("methods").set(null, methods.toArray(new Method[0]));
(2)、Proxy类对象动态生成
// create Proxy class.
String fcn = Proxy.class.getName() + id;
ccm = ClassGenerator.newInstance(cl);
ccm.setClassName(fcn);
ccm.addDefaultConstructor();
ccm.setSuperClass(Proxy.class);
ccm.addMethod("public Object newInstance(" + InvocationHandler.class.getName() + " h){ return new " + pcn + "($1); }");
Class> pc = ccm.toClass();
proxy = (Proxy) pc.newInstance();
这里使用javassist 来动态编写Proxy 这个类的字节码文件并加载生成Class对象,之后返回Proxy实例对象。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.apache.dubbo.common.bytecode;
import java.lang.reflect.InvocationHandler;
import org.apache.dubbo.common.bytecode.ClassGenerator.DC;
public class Proxy0 extends Proxy implements DC {
public Object newInstance(InvocationHandler var1) {
return new proxy0(var1);
}
public Proxy0() {
}
}
dubbo中代理类的获取都是调用的ClassGenerator 类方法,但是ClassGenerator中封装了javassist的ClassPool、CtClass、CtMethod。而具体的代理类获取操作是在Proxy类中进行,如果对具体生成代理类感兴趣可以看看Proxy、ClassGenerator两个类。