Java 动态代理JDK实现与CGLIB实现
https://github.com/Haiyoung/learning-and-preparing-for-interview/blob/master/java_proxy_and_cglib.md
代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。就是这样,真正的业务功能还是有委托类来实现,但是在实现业务类之前的一些公共服务。例如在项目开发中我们没有加入缓冲,日志这些功能,后期想加入,我们就可以使用代理来实现,而没有必要打开已经封装好的委托类。
所谓静态代理也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就已经确定了。
public interface Subject {
public void hello();
public void hello(String arg);
}
public class RealSubject implements Subject{
@Override
public void hello() {
System.out.println("hello world");
}
@Override
public void hello(String arg) {
System.out.println("hello "+arg);
}
}
public class Proxy extends RealSubject implements Subject {
private Subject subject;
public Proxy(Subject subject){
this.subject = subject;
}
@Override
public void hello() {
System.out.println("before ... ... ...");
subject.hello();
System.out.println("after ... ... ...");
}
@Override
public void hello(String arg) {
System.out.println("before ... ... ...");
subject.hello(arg);
System.out.println("after ... ... ...");
}
}
public class ProxyTest {
public static void main(String[] args){
Subject realSubject = new RealSubject();
Proxy staticProxy = new Proxy(realSubject);
staticProxy.hello();
staticProxy.hello("Haiyoung");
}
}
/*before ... ... ...
hello world
after ... ... ...
before ... ... ...
hello Haiyoung
after ... ... ...*/
所谓动态代理,就是代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。
public interface InvocationHandler {
/**
*
* @param proxy 代理对象
* @param method 委托类的方法
* @param args 委托类方法参数
* @return 委托类方法返回值
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxy implements InvocationHandler {
private Object obj;
public Object bind(Object obj){
this.obj = obj;
// 返回代理类实例
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在代理真实对象前我们可以添加一些自己的操作
System.out.println("before ... ... ...");
System.out.println("Method:" + method);
// 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
Object res = method.invoke(obj, args);
// 在代理真实对象后我们也可以添加一些自己的操作
System.out.println("after ... ... ...");
return res;
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class DyProxyTest {
public static void main(String[] args){
Subject subject = (Subject) new DynamicProxy().bind(new RealSubject());
subject.hello();
subject.hello("DynamicProxy");
}
}
/*
before ... ... ...
Method:public abstract void com.haiyoung.ProxyTest.Subject.hello()
hello world
after ... ... ...
before ... ... ...
Method:public abstract void com.haiyoung.ProxyTest.Subject.hello(java.lang.String)
hello DynamicProxy
after ... ... ...*/
其中,代理类继承目标类,并为所有方法生成一个MethodProxy用于代理目标方法,在调用代理类的方法时,会委托MethodInterceptor调用intercept方法。
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxy {
private Object obj;
public Object bind(final Object target){
this.obj = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(obj.getClass());
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("before... this is cglib proxy");
Object res = method.invoke(target, objects);
System.out.println("after... this is cglib proxy");
return res;
}
});
return enhancer.create();
}
}
public class CglibProxyTest {
public static void main(String[] args){
Subject subject = (Subject) new CglibProxy().bind(new RealSubject());
subject.hello();
subject.hello("CglibProxy");
}
}
/*
before... this is cglib proxy
hello world
after... this is cglib proxy
before... this is cglib proxy
hello CglibProxy
after... this is cglib proxy*/