设计模式-代理模式

53 阅读2分钟

代理模式定义:为其他对象提供一种代理以控制对这个对象的访问

通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。

静态代理:在编译时就已经将接口、被代理类、代理类等确定下来。

    interface ShoppingService {
        void go();
    }

    public static class ShoppingServiceImpl implements ShoppingService {

        @Override
        public void go () {
            System.out.println("正在购物呢");
        }
    }

    public static class ShoppingServiceProxy implements ShoppingService {

        private final ShoppingService service;

        public ShoppingServiceProxy (ShoppingService service) {
            this.service = service;
        }

        @Override
        public void go () {
            System.out.println("准备去购物啦");
            service.go();
            System.out.println("购物完回家咯");
        }
    }

    public static void main (String[] args) {

        // 真实对象
        ShoppingService service = new ShoppingServiceImpl();

        // 代理对象
        ShoppingServiceProxy serviceProxy = new ShoppingServiceProxy(service);
        serviceProxy.go();
    }

缺点:代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护

动态代理:在编译期间无法确定需要代理的类。运行期间动态生成代理类

JDK动态代理是通过重写被代理对象实现的接口中的方法来实现

interface ShoppingService {
    void go();
}

public static class ShoppingServiceImpl implements ShoppingService {

    @Override
    public void go () {
        System.out.println("正在购物呢");
    }
}


public static class DynamicProxy implements InvocationHandler{

    // 真实代理对象 -> Service 实现类
    private final Object service;

    // DynamicProxy 代理 Service 实现类
    public DynamicProxy (Object service) {
        this.service = service;
    }

    @Override
    public Object invoke (Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("准备去购物啦");
        method.invoke(service, args);
        System.out.println("购物完回家咯");
        return null;
    }
}

public static void main (String[] args) {

    // 真实对象
    ShoppingService service = new ShoppingServiceImpl();

    // 代理对象
    InvocationHandler handler = new DynamicProxy(service);
    ShoppingService serviceProxy = (ShoppingService) Proxy.newProxyInstance(service.getClass().getClassLoader(), service.getClass().getInterfaces(), handler);
    serviceProxy.go();
}

jdk动态代理只能基于接口进行代理(因为代理对象已经继承了proxy了)

CGLIB是通过继承被代理对象来实现

interface ShoppingService {
    void go();
}

public static class ShoppingServiceImpl implements ShoppingService {

    @Override
    public void go () {
        System.out.println("正在购物呢");
    }
}

public static class MyInterceptor implements MethodInterceptor {

    private Object target;
    public MyInterceptor(Object object){
        this.target = object;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib before!");
        Object invoke = methodProxy.invoke(target, objects);
        System.out.println("cglib after!");
        return invoke;
    }
}


public static void main (String[] args) {

    // 真实对象
    ShoppingService service = new ShoppingServiceImpl();

    MyInterceptor interceptor = new MyInterceptor(service);

    //通过 CGLIB 动态代理获取代理对象的过程
    Enhancer enhancer = new Enhancer();

    //设置父类,因为 cglib 是针对指定的类生成一个子类,所以需要父类
    enhancer.setSuperclass(ShoppingServiceImpl.class);

    //设置回调
    enhancer.setCallback(interceptor);

    //生成代理对象
    ShoppingServiceImpl actorProxy = (ShoppingServiceImpl)enhancer.create();

}

两种方式的区别:

JDK动态代理:利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
CGlib动态代理:利用ASM(开源的Java字节码编辑库,操作字节码)开源包,将代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。