设计模式-代理模式

166 阅读2分钟

这里仅介绍JDK动态代理和Cglib

JDK动态代理

public interface IPerson {
    void findLove();
}

public class Zhangsan implements IPerson {
    public void findLove() {
        System.out.println("张三要求:肤白貌美大长腿");
    }
}

public class ZhaoLiu implements IPerson {
    public void findLove() {
        System.out.println("赵六要求:有车有房学历高");
    }
}

//下面是实现一个JDK版本的动态代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkMeipo implements InvocationHandler {
    private IPerson target;//动态代理之所以是动态,是不管目标对象是啥,都可以代理,静态代理只能代理指定对象,只能硬编码实现。
    public IPerson getInstance(IPerson target){
        this.target = target;
        Class<?> clazz =  target.getClass();
        //下面这个方法是JDK动态代理的核心方法
        return (IPerson) Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object result = method.invoke(this.target,args);
        after();
        return result;
    }

    private void after() {
        System.out.println("双方同意,开始交往");
    }

    private void before() {
        System.out.println("我是媒婆,已经收集到你的需求,开始物色");
    }
}
//测试
public class Test {
    public static void main(String[] args) {
        JdkMeipo jdkMeipo = new JdkMeipo();
        IPerson zhangsan = jdkMeipo.getInstance(new Zhangsan());
        zhangsan.findLove();
        
        IPerson zhaoliu = jdkMeipo.getInstance(new ZhaoLiu());
        zhaoliu.findLove();
    }
}

Cglib动态代理:

public class Zhangsan{
    public void findLove() {
        System.out.println("张三要求:肤白貌美大长腿");
    }
}

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CGlibMeipo implements MethodInterceptor {
    public Object getInstance(Class<?> clazz) throws Exception{
        //相当于Proxy,代理的工具类
        //这里是继承写法,直接是继承出了一个新的类。
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        before();
        Object obj = methodProxy.invokeSuper(o,objects);
        after();
        return obj;
    }
    private void before(){
        System.out.println("我是媒婆,我要给你找对象,现在已经确认你的需求");
        System.out.println("开始物色");
    }
    private void after(){
        System.out.println("OK的话,准备办事");
    }
}

//测试
public class Test {
    public static void main(String[] args) {
        Customer obj = (Customer) new CGlibMeipo().getInstance(Customer.class);
        System.out.println(obj);
        obj.findLove();
    }
}

JDK动态代理和Cglib动态代理的区别:

1),JDK动态代理实现了被代理对象的接口,Cglib代理继承了被代理对象。
2),JDK动态代理和Cglib动态代理都在运行期生成字节码,JDK动态代理直接写Class字节码,
    Cglib代理使用ASM框架写Class字节码,Cglib的实现更复杂,所以生成代理类比JDK动态代理效率低。
3),JDK动态代理调用代理方法是通过反射机制调用的,Cglib代理是通过FastClass机制直接调用方法的。
    Cglib采用了FastClass机制,它的原理很简单:为代理类和被代理类各生成一个类,这个类会为代理类或被代
    理类的方法分配一个index(int类型);这个index当做一个入参,FastClass就可以直接定位要调用的方法
    并直接调用,省去了反射调用,所以调用效率比JDK代理通过反射调用高。