基于javassist实现对接口的动态代理引擎

一提到jdk中的java.lang.reflect.Proxy,用过spring,hibernate等框架的人应该都有所了解,对!就是动态代理。AOP - 面向切面编程 - 就是基于动态代理实现的。

平日里项目中用spring aop框架进行日志拦截和声明式事务处理确实很方便好用,从另一种角度将代码解耦,极大的提高了代码的灵活性和可扩展性,在获益的同时我们不得不惊叹aop框架的神奇,但是静下心来想一想:它的核心 - 动态代理 - 其实是依靠运行时动态在内存中实现要代理的接口,并在所有接口的方法实现中反射java.lang.reflect.InvocationHandler的invoke方法;所以要用动态代理就必须先实现自己的InvocationHandler;返回给用户的是代理对象本身,而非接口的原有实现。

想明白了代理的本质,实现它就很容易了,我们可以借助开源的动态生成字节码/类的项目,如:

Byte Code Engineering Library (BCEL) - 在实际的JVM 指令层次上进行操作,提供在运行时在内存中动态生成类的支持

Javassist - 提供类似BCEL的功能,不过它更强调源代码级别的工作,对于程序员来说更加容易上手

好了,废话不多说了,现在看看我用Javassist实现的动态代理,提供接近java.lang.reflect.Proxy的功能


package com.cuishen.myAop;

import java.lang.reflect.Method;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.NotFoundException;
import javassist.CtMethod;
import javassist.CtNewMethod;

/**
* 基于javassist实现的动态代理类,即在运行时在内存中动态生成要代理的接口的实现,并在接口的方法实现中反射
* com.cuishen.myAop.InterceptorHandler(拦截器接口)的invoke方法,所以在使用本代理之前请先实现
* 拦截器接口。本代理提供接近java.lang.reflect.Proxy的功能
* @author cuishen
* @version 1.0
* @see com.cuishen.myAop.InterceptorHandler
* @see java.lang.reflect.Proxy
*/
public class MyProxyImpl {
/** 动态代理类的类名后缀 */
private final static String PROXY_CLASS_NAME_SUFFIX = "$MyProxy_";
/** 拦截器接口 */
private final static String INTERCEPTOR_HANDLER_INTERFACE = "com.cuishen.myAop.InterceptorHandler";
/** 动态代理类的类名索引,防止类名重复 */
private static int proxyClassIndex = 1;

/**
* 暴露给用户的动态代理接口,返回某个接口的动态代理对象,注意本代理实现需和com.cuishen.myAop.InterceptorHandler拦截器配合
* 使用,即用户要使用本动态代理,需先实现com.cuishen.myAop.InterceptorHandler拦截器接口
* <br>
* 使用方法如下:
* <br>
* <code>
* StudentInfoService studentInfo = (StudentInfoService)MyProxyImpl.newProxyInstance(String, String, String);
* <br>studentInfo.方法调用;
* </code>
* @param interfaceClassName String 要动态代理的接口类名, e.g test.StudentInfoService
* @param classToProxy String 要动态代理的接口的实现类的类名, e.g test.StudentInfoServiceImpl
* @param interceptorHandlerImplClassName String 用户提供的拦截器接口的实现类的类名
* @return Object 返回某个接口的动态代理对象
* @throws InstantiationException
* @throws IllegalAccessException
* @throws NotFoundException
* @throws CannotCompileException
* @throws ClassNotFoundException
* @see com.cuishen.myAop.InterceptorHandler
*/
public static Object newProxyInstance(String interfaceClassName, String classToProxy, String interceptorHandlerImplClassName) throws InstantiationException, IllegalAccessException, NotFoundException, CannotCompileException, ClassNotFoundException {
Class interfaceClass = Class.forName(interfaceClassName);
Class interceptorHandlerImplClass = Class.forName(interceptorHandlerImplClassName);
return dynamicImplementsInterface(classToProxy, interfaceClass, interceptorHandlerImplClass);
}

/**
* 动态实现要代理的接口
* @param classToProxy String 要动态代理的接口的实现类的类名, e.g test.StudentInfoServiceImpl
* @param interfaceClass Class 要动态代理的接口类, e.g test.StudentInfoService
* @param interceptorHandlerImplClass Class 用户提供的拦截器接口的实现类
* @return Object 返回某个接口的动态代理对象
* @throws NotFoundException
* @throws CannotCompileException
* @throws InstantiationException
* @throws IllegalAccessException
*/
private static Object dynamicImplementsInterface(String classToProxy, Class interfaceClass, Class interceptorHandlerImplClass) throws NotFoundException, CannotCompileException, InstantiationException, IllegalAccessException {
ClassPool cp = ClassPool.getDefault();
String interfaceName = interfaceClass.getName();
//动态指定代理类的类名
String proxyClassName = interfaceName + PROXY_CLASS_NAME_SUFFIX + proxyClassIndex++;
//要实现的接口的包名+接口名
String interfaceNamePath = interfaceName;

CtClass ctInterface = cp.getCtClass(interfaceNamePath);
CtClass cc = cp.makeClass(proxyClassName);
cc.addInterface(ctInterface);
Method [] methods = interfaceClass.getMethods();
for(int i = 0; i < methods.length; i++) {
Method method = methods[i];
dynamicImplementsMethodsFromInterface(classToProxy, cc, method, interceptorHandlerImplClass, i);
}
return (Object)cc.toClass().newInstance();
}

/**
* 动态实现接口里的方法
* @param classToProxy String 要动态代理的接口的实现类的类名, e.g test.StudentInfoServiceImpl
* @param implementer CtClass 动态代理类的包装
* @param methodToImpl Method 动态代理类里面要实现的接口方法的包装
* @param interceptorClass Class 用户提供的拦截器实现类
* @param methodIndex int 要实现的方法的索引
* @throws CannotCompileException
*/
private static void dynamicImplementsMethodsFromInterface(String classToProxy, CtClass implementer, Method methodToImpl, Class interceptorClass, int methodIndex) throws CannotCompileException {
String methodCode = generateMethodCode(classToProxy, methodToImpl, interceptorClass, methodIndex);
CtMethod cm = CtNewMethod.make(methodCode, implementer);
implementer.addMethod(cm);
}

/**
* 动态组装方法体,当然代理里面的方法实现并不是简单的方法拷贝,而是反射调用了拦截器里的invoke方法,并将接收到的参数进行传递
* @param classToProxy String 要动态代理的接口的实现类的类名, e.g test.StudentInfoServiceImpl
* @param methodToImpl Method 动态代理类里面要实现的接口方法的包装
* @param interceptorClass Class 用户提供的拦截器实现类
* @param methodIndex int 要实现的方法的索引
* @return String 动态组装的方法的字符串
*/
private static String generateMethodCode(String classToProxy, Method methodToImpl, Class interceptorClass, int methodIndex) {
String methodName = methodToImpl.getName();
String methodReturnType = methodToImpl.getReturnType().getName();
Class []parameters = methodToImpl.getParameterTypes();
Class []exceptionTypes = methodToImpl.getExceptionTypes();
StringBuffer exceptionBuffer = new StringBuffer();
//组装方法的Exception声明
if(exceptionTypes.length > 0) exceptionBuffer.append(" throws ");
for(int i = 0; i < exceptionTypes.length; i++) {
if(i != exceptionTypes.length - 1) exceptionBuffer.append(exceptionTypes[i].getName()).append(",");
else exceptionBuffer.append(exceptionTypes[i].getName());
}
StringBuffer parameterBuffer = new StringBuffer();
//组装方法的参数列表
for(int i = 0; i < parameters.length; i++) {
Class parameter = parameters[i];
String parameterType = parameter.getName();
//动态指定方法参数的变量名
String refName = "a" + i;
if(i != parameters.length - 1) parameterBuffer.append(parameterType).append(" " + refName).append(",");
else parameterBuffer.append(parameterType).append(" " + refName);
}
StringBuffer methodDeclare = new StringBuffer();
//方法声明,由于是实现接口的方法,所以是public
methodDeclare.append("public ").append(methodReturnType).append(" ").append(methodName).append("(").append(parameterBuffer).append(")").append(exceptionBuffer).append(" {\n");
String interceptorImplName = interceptorClass.getName();
//方法体
methodDeclare.append(INTERCEPTOR_HANDLER_INTERFACE).append(" interceptor = new ").append(interceptorImplName).append("();\n");
//反射调用用户的拦截器接口
methodDeclare.append("Object returnObj = interceptor.invoke(Class.forName(\"" + classToProxy + "\").newInstance(), Class.forName(\"" + classToProxy + "\").getMethods()[" + methodIndex + "], ");
//传递方法里的参数
if(parameters.length > 0) methodDeclare.append("new Object[]{");
for(int i = 0; i < parameters.length; i++) {
//($w) converts from a primitive type to the corresponding wrapper type: e.g.
//Integer i = ($w)5;
if(i != parameters.length - 1) methodDeclare.append("($w)a" + i + ",");
else methodDeclare.append("($w)a" + i);
}
if(parameters.length > 0) methodDeclare.append("});\n");
else methodDeclare.append("null);\n");
//对调用拦截器的返回值进行包装
if(methodToImpl.getReturnType().isPrimitive()) {
if(methodToImpl.getReturnType().equals(Boolean.TYPE)) methodDeclare.append("return ((Boolean)returnObj).booleanValue();\n");
else if(methodToImpl.getReturnType().equals(Integer.TYPE)) methodDeclare.append("return ((Integer)returnObj).intValue();\n");
else if(methodToImpl.getReturnType().equals(Long.TYPE)) methodDeclare.append("return ((Long)returnObj).longValue();\n");
else if(methodToImpl.getReturnType().equals(Float.TYPE)) methodDeclare.append("return ((Float)returnObj).floatValue();\n");
else if(methodToImpl.getReturnType().equals(Double.TYPE)) methodDeclare.append("return ((Double)returnObj).doubleValue();\n");
else if(methodToImpl.getReturnType().equals(Character.TYPE)) methodDeclare.append("return ((Character)returnObj).charValue();\n");
else if(methodToImpl.getReturnType().equals(Byte.TYPE)) methodDeclare.append("return ((Byte)returnObj).byteValue();\n");
else if(methodToImpl.getReturnType().equals(Short.TYPE)) methodDeclare.append("return ((Short)returnObj).shortValue();\n");
} else {
methodDeclare.append("return (" + methodReturnType + ")returnObj;\n");
}
methodDeclare.append("}");
System.out.println(methodDeclare.toString());
return methodDeclare.toString();
}

}


我也提供了类似于java.lang.reflect.InvocationHandler的接口,我暂且称其为拦截器接口,要用我的代理,就得先实现它


package com.cuishen.myAop;

import java.lang.reflect.Method;

/**
* 拦截器接口,用户使用com.cuishen.myAop.MyProxyImpl动态代理前,请先实现本接口,
* 在执行动态代理对象的方法时会自动反射到invoke方法,被代理的对象、方法和参数将做为
* 参数传递给invoke方法
* @author cuishen
* @version 1.0
* @see com.cuishen.myAop.MyProxyImpl
*/
public interface InterceptorHandler {

/**
* 调用动态代理对象的方法将反射本方法,可在本方法实现中添加类似AOP的事前事后操作,只有在本方法体中加入如下代码
* <br>
* <code>
* Object returnObj = method.invoke(obj, args);
* <br>
* ...
* <br>
* return returnObj;
* </code>
* <br>
* 被代理的方法才会被执行,返回值将返回给代理最后返回给程序
* @param obj Object 被代理的对象
* @param method Method 被代理对象的方法
* @param args Object[] 被代理对象的方法的参数
* @return Object 被代理对象的方法执行后的返回值
* @throws Throwable
*/
public Object invoke(Object obj, Method method, Object[] args) throws Throwable;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值