利用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的功能

Java代码 复制代码 收藏代码
  1. package com.cuishen.myAop;
  2. import java.lang.reflect.Method;
  3. import javassist.CannotCompileException;
  4. import javassist.ClassPool;
  5. import javassist.CtClass;
  6. import javassist.NotFoundException;
  7. import javassist.CtMethod;
  8. import javassist.CtNewMethod;
  9. /**
  10. * 基于javassist实现的动态代理类,即在运行时在内存中动态生成要代理的接口的实现,并在接口的方法实现中反射
  11. * com.cuishen.myAop.InterceptorHandler(拦截器接口)的invoke方法,所以在使用本代理之前请先实现
  12. * 拦截器接口。本代理提供接近java.lang.reflect.Proxy的功能
  13. * @author cuishen
  14. * @version 1.0
  15. * @see com.cuishen.myAop.InterceptorHandler
  16. * @see java.lang.reflect.Proxy
  17. */
  18. public class MyProxyImpl {
  19. /** 动态代理类的类名后缀 */
  20. private final static String PROXY_CLASS_NAME_SUFFIX = "$MyProxy_";
  21. /** 拦截器接口 */
  22. private final static String INTERCEPTOR_HANDLER_INTERFACE = "com.cuishen.myAop.InterceptorHandler";
  23. /** 动态代理类的类名索引,防止类名重复 */
  24. private static int proxyClassIndex = 1;
  25. /**
  26. * 暴露给用户的动态代理接口,返回某个接口的动态代理对象,注意本代理实现需和com.cuishen.myAop.InterceptorHandler拦截器配合
  27. * 使用,即用户要使用本动态代理,需先实现com.cuishen.myAop.InterceptorHandler拦截器接口
  28. * <br>
  29. * 使用方法如下:
  30. * <br>
  31. * <code>
  32. * StudentInfoService studentInfo = (StudentInfoService)MyProxyImpl.newProxyInstance(String, String, String);
  33. * <br>studentInfo.方法调用;
  34. * </code>
  35. * @param interfaceClassName String 要动态代理的接口类名, e.g test.StudentInfoService
  36. * @param classToProxy String 要动态代理的接口的实现类的类名, e.g test.StudentInfoServiceImpl
  37. * @param interceptorHandlerImplClassName String 用户提供的拦截器接口的实现类的类名
  38. * @return Object 返回某个接口的动态代理对象
  39. * @throws InstantiationException
  40. * @throws IllegalAccessException
  41. * @throws NotFoundException
  42. * @throws CannotCompileException
  43. * @throws ClassNotFoundException
  44. * @see com.cuishen.myAop.InterceptorHandler
  45. */
  46. public static Object newProxyInstance(String interfaceClassName, String classToProxy, String interceptorHandlerImplClassName) throws InstantiationException, IllegalAccessException, NotFoundException, CannotCompileException, ClassNotFoundException {
  47. Class interfaceClass = Class.forName(interfaceClassName);
  48. Class interceptorHandlerImplClass = Class.forName(interceptorHandlerImplClassName);
  49. return dynamicImplementsInterface(classToProxy, interfaceClass, interceptorHandlerImplClass);
  50. }
  51. /**
  52. * 动态实现要代理的接口
  53. * @param classToProxy String 要动态代理的接口的实现类的类名, e.g test.StudentInfoServiceImpl
  54. * @param interfaceClass Class 要动态代理的接口类, e.g test.StudentInfoService
  55. * @param interceptorHandlerImplClass Class 用户提供的拦截器接口的实现类
  56. * @return Object 返回某个接口的动态代理对象
  57. * @throws NotFoundException
  58. * @throws CannotCompileException
  59. * @throws InstantiationException
  60. * @throws IllegalAccessException
  61. */
  62. private static Object dynamicImplementsInterface(String classToProxy, Class interfaceClass, Class interceptorHandlerImplClass) throws NotFoundException, CannotCompileException, InstantiationException, IllegalAccessException {
  63. ClassPool cp = ClassPool.getDefault();
  64. String interfaceName = interfaceClass.getName();
  65. //动态指定代理类的类名
  66. String proxyClassName = interfaceName + PROXY_CLASS_NAME_SUFFIX + proxyClassIndex++;
  67. //要实现的接口的包名+接口名
  68. String interfaceNamePath = interfaceName;
  69. CtClass ctInterface = cp.getCtClass(interfaceNamePath);
  70. CtClass cc = cp.makeClass(proxyClassName);
  71. cc.addInterface(ctInterface);
  72. Method [] methods = interfaceClass.getMethods();
  73. for(int i = 0; i < methods.length; i++) {
  74. Method method = methods[i];
  75. dynamicImplementsMethodsFromInterface(classToProxy, cc, method, interceptorHandlerImplClass, i);
  76. }
  77. return (Object)cc.toClass().newInstance();
  78. }
  79. /**
  80. * 动态实现接口里的方法
  81. * @param classToProxy String 要动态代理的接口的实现类的类名, e.g test.StudentInfoServiceImpl
  82. * @param implementer CtClass 动态代理类的包装
  83. * @param methodToImpl Method 动态代理类里面要实现的接口方法的包装
  84. * @param interceptorClass Class 用户提供的拦截器实现类
  85. * @param methodIndex int 要实现的方法的索引
  86. * @throws CannotCompileException
  87. */
  88. private static void dynamicImplementsMethodsFromInterface(String classToProxy, CtClass implementer, Method methodToImpl, Class interceptorClass, int methodIndex) throws CannotCompileException {
  89. String methodCode = generateMethodCode(classToProxy, methodToImpl, interceptorClass, methodIndex);
  90. CtMethod cm = CtNewMethod.make(methodCode, implementer);
  91. implementer.addMethod(cm);
  92. }
  93. /**
  94. * 动态组装方法体,当然代理里面的方法实现并不是简单的方法拷贝,而是反射调用了拦截器里的invoke方法,并将接收到的参数进行传递
  95. * @param classToProxy String 要动态代理的接口的实现类的类名, e.g test.StudentInfoServiceImpl
  96. * @param methodToImpl Method 动态代理类里面要实现的接口方法的包装
  97. * @param interceptorClass Class 用户提供的拦截器实现类
  98. * @param methodIndex int 要实现的方法的索引
  99. * @return String 动态组装的方法的字符串
  100. */
  101. private static String generateMethodCode(String classToProxy, Method methodToImpl, Class interceptorClass, int methodIndex) {
  102. String methodName = methodToImpl.getName();
  103. String methodReturnType = methodToImpl.getReturnType().getName();
  104. Class []parameters = methodToImpl.getParameterTypes();
  105. Class []exceptionTypes = methodToImpl.getExceptionTypes();
  106. StringBuffer exceptionBuffer = new StringBuffer();
  107. //组装方法的Exception声明
  108. if(exceptionTypes.length > 0) exceptionBuffer.append(" throws ");
  109. for(int i = 0; i < exceptionTypes.length; i++) {
  110. if(i != exceptionTypes.length - 1) exceptionBuffer.append(exceptionTypes[i].getName()).append(",");
  111. else exceptionBuffer.append(exceptionTypes[i].getName());
  112. }
  113. StringBuffer parameterBuffer = new StringBuffer();
  114. //组装方法的参数列表
  115. for(int i = 0; i < parameters.length; i++) {
  116. Class parameter = parameters[i];
  117. String parameterType = parameter.getName();
  118. //动态指定方法参数的变量名
  119. String refName = "a" + i;
  120. if(i != parameters.length - 1) parameterBuffer.append(parameterType).append(" " + refName).append(",");
  121. else parameterBuffer.append(parameterType).append(" " + refName);
  122. }
  123. StringBuffer methodDeclare = new StringBuffer();
  124. //方法声明,由于是实现接口的方法,所以是public
  125. methodDeclare.append("public ").append(methodReturnType).append(" ").append(methodName).append("(").append(parameterBuffer).append(")").append(exceptionBuffer).append(" {\n");
  126. String interceptorImplName = interceptorClass.getName();
  127. //方法体
  128. methodDeclare.append(INTERCEPTOR_HANDLER_INTERFACE).append(" interceptor = new ").append(interceptorImplName).append("();\n");
  129. //反射调用用户的拦截器接口
  130. methodDeclare.append("Object returnObj = interceptor.invoke(Class.forName(\"" + classToProxy + "\").newInstance(), Class.forName(\"" + classToProxy + "\").getMethods()[" + methodIndex + "], ");
  131. //传递方法里的参数
  132. if(parameters.length > 0) methodDeclare.append("new Object[]{");
  133. for(int i = 0; i < parameters.length; i++) {
  134. //($w) converts from a primitive type to the corresponding wrapper type: e.g.
  135. //Integer i = ($w)5;
  136. if(i != parameters.length - 1) methodDeclare.append("($w)a" + i + ",");
  137. else methodDeclare.append("($w)a" + i);
  138. }
  139. if(parameters.length > 0) methodDeclare.append("});\n");
  140. else methodDeclare.append("null);\n");
  141. //对调用拦截器的返回值进行包装
  142. if(methodToImpl.getReturnType().isPrimitive()) {
  143. if(methodToImpl.getReturnType().equals(Boolean.TYPE)) methodDeclare.append("return ((Boolean)returnObj).booleanValue();\n");
  144. else if(methodToImpl.getReturnType().equals(Integer.TYPE)) methodDeclare.append("return ((Integer)returnObj).intValue();\n");
  145. else if(methodToImpl.getReturnType().equals(Long.TYPE)) methodDeclare.append("return ((Long)returnObj).longValue();\n");
  146. else if(methodToImpl.getReturnType().equals(Float.TYPE)) methodDeclare.append("return ((Float)returnObj).floatValue();\n");
  147. else if(methodToImpl.getReturnType().equals(Double.TYPE)) methodDeclare.append("return ((Double)returnObj).doubleValue();\n");
  148. else if(methodToImpl.getReturnType().equals(Character.TYPE)) methodDeclare.append("return ((Character)returnObj).charValue();\n");
  149. else if(methodToImpl.getReturnType().equals(Byte.TYPE)) methodDeclare.append("return ((Byte)returnObj).byteValue();\n");
  150. else if(methodToImpl.getReturnType().equals(Short.TYPE)) methodDeclare.append("return ((Short)returnObj).shortValue();\n");
  151. } else {
  152. methodDeclare.append("return (" + methodReturnType + ")returnObj;\n");
  153. }
  154. methodDeclare.append("}");
  155. System.out.println(methodDeclare.toString());
  156. return methodDeclare.toString();
  157. }
  158. }
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的接口,我暂且称其为拦截器接口,要用我的代理,就得先实现它

Java代码 复制代码 收藏代码
  1. package com.cuishen.myAop;
  2. import java.lang.reflect.Method;
  3. /**
  4. * 拦截器接口,用户使用com.cuishen.myAop.MyProxyImpl动态代理前,请先实现本接口,
  5. * 在执行动态代理对象的方法时会自动反射到invoke方法,被代理的对象、方法和参数将做为
  6. * 参数传递给invoke方法
  7. * @author cuishen
  8. * @version 1.0
  9. * @see com.cuishen.myAop.MyProxyImpl
  10. */
  11. public interface InterceptorHandler {
  12. /**
  13. * 调用动态代理对象的方法将反射本方法,可在本方法实现中添加类似AOP的事前事后操作,只有在本方法体中加入如下代码
  14. * <br>
  15. * <code>
  16. * Object returnObj = method.invoke(obj, args);
  17. * <br>
  18. * ...
  19. * <br>
  20. * return returnObj;
  21. * </code>
  22. * <br>
  23. * 被代理的方法才会被执行,返回值将返回给代理最后返回给程序
  24. * @param obj Object 被代理的对象
  25. * @param method Method 被代理对象的方法
  26. * @param args Object[] 被代理对象的方法的参数
  27. * @return Object 被代理对象的方法执行后的返回值
  28. * @throws Throwable
  29. */
  30. public Object invoke(Object obj, Method method, Object[] args) throws Throwable;
  31. }  
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值