浏览 3185 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2009-07-07
平日里项目中用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; } 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |