利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
利用ASM(开源的Java字节码编辑库,操作字节码)开源包,将代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
JDK代理只能对实现接口的类生成代理;CGlib是针对类实现代理,对指定的类生成一个子类,并覆盖其中的方法,这种通过继承类的实现方式,不能代理final修饰的类。
/** * 目标接口类 */ public interface UserManager { void addUser(String username, String password); void delUser(String username); }
/** * 动态代理: * 1. 特点:字节码随用随创建,随用随加载 * 2. 作用:不修改源码的基础上对方法增强 * 3. 分类: * 1)基于接口的动态代理 * 1. 基于接口的动态代理: * 1)涉及的类:Proxy * 2)提供者:JDK官方 * 3)如何创建代理对象: * 使用Proxy类中的newProxyInstance方法 * 4)创建代理对象的要求 * 被代理类最少实现一个接口,如果没有则不能使用 * 5)newProxyInstance方法的参数: * ClassLoader:类加载器,它是用于加载代理对象字节码的。和被代理对象使用相同的类加载器。固定写法。 * Class[]:字节码数组,它是用于让代理对象和被代理对象有相同方法。固定写法。 * InvocationHandler:用于提供增强的代码,它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类 * 2)基于子类的动态代理 */ public class JDKProxy implements InvocationHandler { // 用于指向被代理对象 private Object targetObject; public Object newProxy(Object targetObject) { // 将被代理对象传入进行代理 this.targetObject = targetObject; // 返回代理对象 return Proxy.newProxyInstance(this.targetObject.getClass().getClassLoader(),this.targetObject.getClass().getInterfaces(),this); } /** * 被代理对象的任何方法执行时,都会被invoke方法替换,即:代理对象执行被代理对象中的任何方法时,实际上执行的时当前的invoke方法 * @param proxy(代理对象的引用) * @param method(当前执行的方法) * @param args(当前执行方法所需的参数) * @return(和被代理对象方法有相同的返回值) * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 在原来的方法上增加了日志打印功能,增强代码 printLog(); Object ret = null; // 调用invoke方法(即执行了代理对象调用被调用对象中的某个方法) ret = method.invoke(targetObject, args); return ret; } /** * 模拟日志打印 */ private void printLog() { System.out.println("日志打印:printLog()"); } }
public class TestJDKProxy { public static void main(String[] args) { UserManager userManager = new UserManagerImpl(); JDKProxy jdkProxy = new JDKProxy(); UserManager userManagerProxy = (UserManager)jdkProxy.newProxy(userManager); System.out.println("--------------------没有使用增强过的方法--------------------"); userManager.addUser("root","root"); userManager.delUser("root"); System.out.println("--------------------使用代理对象增强过的方法--------------------"); userManagerProxy.addUser("scott","tiger"); userManagerProxy.delUser("scott"); } }
--------------------没有使用增强过的方法-------------------- 调用了UserManagerImpl.addUser()方法! 调用了UserManagerImpl.delUser()方法! --------------------使用代理对象增强过的方法-------------------- 日志打印:printLog() 调用了UserManagerImpl.addUser()方法! 日志打印:printLog() 调用了UserManagerImpl.delUser()方法!
/** * 动态代理: * 1. 特点:字节码随用随创建,随用随加载 * 2. 作用:不修改源码的基础上对方法增强 * 3. 分类: * 1)基于接口的动态代理 * 2)基于子类的动态代理 * 1. 基于子类的动态代理: * 1)涉及的类:Enhancer * 2)提供者:第三方cglib库 * 3)如何创建代理对象: * 使用Enhancer类中的create方法 * 4)创建代理对象的要求 * 被代理类不能是最终类 * 5)create方法的参数: * Class:字节码,它是用于指定被代理对象的字节码。固定写法。 * Callback():用于提供增强的代码,它是让我们写如何代理。我们一般都是些一个该接口的实现类。固定写法。 */ public class CGLibProxy implements MethodInterceptor { // 用于指向被代理对象 private Object targetObject; // 用于创建代理对象 public Object createProxy(Object targetObject) { this.targetObject = targetObject; return new Enhancer().create(this.targetObject.getClass(),this); } /** * * @param proxy(代理对象的引用) * @param method(当前执行的方法) * @param args(当前执行方法所需的参数) * @param methodProxy(当前执行方法的代理对象) * @return(和被代理对象方法有相同的返回值) * @throws Throwable */ @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object ret = null; // 过滤方法 if ("addUser".equals(method.getName())) { // 日志打印 printLog(); } ret = method.invoke(targetObject, args); return ret; } /** * 模拟日志打印 */ private void printLog() { System.out.println("日志打印:printLog()"); } }
public class TestCGLibProxy { public static void main(String[] args) { CGLibProxy cgLibProxy = new CGLibProxy(); UserManager userManager = new UserManagerImpl(); UserManager cgLibProxyProxy = (UserManager)cgLibProxy.createProxy(userManager); System.out.println("--------------------没有使用增强过的方法--------------------"); userManager.addUser("root","root"); userManager.delUser("root"); System.out.println("--------------------使用代理对象增强过的方法--------------------"); cgLibProxyProxy.addUser("scott","tiger"); cgLibProxyProxy.delUser("scott"); } }
--------------------没有使用增强过的方法-------------------- 调用了UserManagerImpl.addUser()方法! 调用了UserManagerImpl.delUser()方法! --------------------使用代理对象增强过的方法-------------------- 日志打印:printLog() 调用了UserManagerImpl.addUser()方法! 调用了UserManagerImpl.delUser()方法!
1)JDK代理使用的是反射机制实现aop的动态代理,CGLIB代理使用字节码处理框架asm,通过修改字节码生成子类。所以jdk动态代理的方式创建代理对象效率较高,执行效率较低,cglib创建效率较低,执行效率高;
2)JDK动态代理机制是委托机制,具体说动态实现接口类,在动态生成的实现类里面委托hanlder去调用原始实现类方法,CGLIB则使用的继承机制,具体说被代理类和代理类是继承关系,所以代理类是可以赋值给被代理类的,如果被代理类有接口,那么代理类也可以赋值给接口。
原文链接: https://blog.csdn.net/weixin_...