前言
继上篇文章,得知动态代理需解决的问题,通过一个代理类完成全部的代理功能。
- 静态代理是在编译时,就确定了要代理的对象。
- 动态代理是在运行时,通过反射机制实现动态代理,并且能够代理各种类型的对象
JDK的动态代理
修改上篇文章的代码为动态代理
- LogProxy
package ProxyPattern.dynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* Created by liqiushi on 2018/1/4.
*/
public class LogProxy implements InvocationHandler {
private Object targetObject;
public Object newProxyInstance(Object targetObject) {
this.targetObject = targetObject;
//第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("invoke() call!");
System.out.println();
Object res = null;
System.out.println("before realSubject!");
res = method.invoke(targetObject, args);
System.out.println("after realSubject!");
return null;
}
}
- TestRunner
package ProxyPattern.dynamicProxy;
public class TestRunner {
public static void main(String[] args) {
LogProxy logProxy = new LogProxy();
Subject subjectProxy = (Subject) logProxy.newProxyInstance(new RealSubject());
subjectProxy.otherFun();
}
}
- 结果
before realSubject!
other something!
after realSubject!
cglib的动态代理
- LogProxy
package ProxyPattern.dynamicProxy.CGLib;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* Created by liqiushi on 2018/1/4.
*/
public class LogProxy implements MethodInterceptor {
/**定义一个拦截器。在调用目标方法时,CGLib会回调MethodInterceptor接口方法拦截,来实现你自己的代理逻辑,类似于JDK中的InvocationHandler接口。
* 代理对象调用方法时,被此拦截
* @param o 动态生成的代理对象
* @param method 委托对象的方法
* @param objects 委托对象的参数
* @param methodProxy CGlib方法代理对象的方法引用
* @return 调用方法返回值
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object result = null;
System.out.println("before realSubject");
//调用代理类实例上的proxy方法的父类方法(即委托类的方法)
result = methodProxy.invokeSuper(o,objects);
System.out.println("after realSubject");
return result;
}
}
- TestRunner
package ProxyPattern.dynamicProxy.CGLib;
import net.sf.cglib.proxy.Enhancer;
public class TestRunner {
public static void main(String[] args) {
//Enhancer 这里Enhancer类是CGLib中的一个字节码增强器,它可以方便的对你想要处理的类进行扩展
Enhancer enhancer = new Enhancer();
//将委托类设置父类
enhancer.setSuperclass(RealSubject.class);
//设置回调拦截
enhancer.setCallback(new LogProxy());
//生成代理对象,需要转型
Subject subject = (RealSubject) enhancer.create();
subject.otherFun();
}
}
jdk和cglib的不同
- java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
- cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理
JDK动态代理和CGLIB字节码生成的区别?
- JDK动态代理只能对实现了接口的类生成代理,而不能针对类
- CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法
因为是继承,所以该类或方法最好不要声明成final
网友评论