JDK动态代理
利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
CGlib动态代理
利用ASM(开源的Java字节码编辑库,操作字节码)开源包,将代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
区别
JDK代理只能对实现接口的类生成代理;CGlib是针对类实现代理,对指定的类生成一个子类,并覆盖其中的方法,这种通过继承类的实现方式,不能代理final修饰的类。
方式一:JDK动态代理
目标接口类
/**
* 目标接口类
*/
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()方法!
方式二:CGlib动态代理
/**
* 动态代理:
* 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则使用的继承机制,具体说被代理类和代理类是继承关系,所以代理类是可以赋值给被代理类的,如果被代理类有接口,那么代理类也可以赋值给接口。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。