Java代理设计模式Proxy的几种具体实现

6次阅读

共计 3216 个字符,预计需要花费 9 分钟才能阅读完成。

Proxy 是一种结构设计模型,主要解决对象直接访问带来的问题, 代理又分为静态代理和动态代理(JDK 代理、CGLIB 代理。
静态代理: 又程序创建的代理类,或者特定的工具类,在平时开发中经常用到这种代理模式,这种一般在程序运行前就已经生成对应的 class 文件;
动态代理:在程序运行时通过反射机制动态创建。

下面通过一个场景实现以下三种代理方式

  • 步骤一:定义商店接口(Subject)
  • 步骤二:个人店家运营(RealSubject)
  • 步骤三:平台运营(proxy)
  • 步骤四:个体消费(client)

几种代理方式都会用到 Subject、RealSubject,现在这里定义
Store.java(Subject): 定义两个接口 operate(运营),business(交易)。

public interface Store {
    /**
     * 店铺运营
     */
    public void operate();

    /**
     * 店铺交易
     */
    public void business();}

PersonStore.java(RealSubject) 单个用户运营

public class PersonStore implements Store {
    @Override
    public void operate() {System.out.println("个人商店运营");
    }

    @Override
    public void business() {System.out.println("个人商店交易");
    }
}

静态代理

静态代理的实现比较简单,代理类通过实现与目标对象相同的接口,并在类中维护一个代理对象, 这种场景用于个体商家比较少的情况,如果多的话代理类十分繁多、不易维护

创建静态代理类

ProxyStroe.java(proxy):在代理平台运营是收取管理费用 100,这个代理类需要实现 Store 接口,并制定目标类 target(PersonStore)。

public class ProxyStroe implements Store{private Store personStore = new PersonStore();

    @Override
    public void operate() {System.out.println("收取管理费用 100 元");
        personStore.operate();}

    @Override
    public void business() {personStore.business();
    }
}

静态代理调用

StaticConsumer.java(client): 通过创建 ProxyStroe 去代理 PersonStore,并进行操作。

public class StaticConsumer {public static void main(String[] args) {ProxyStroe store = new ProxyStroe();
        store.operate();
        store.business();}
}

动态代理

JDK 代理

动态代理类是通过接口实现的, 利用拦截器 (拦截器必须实现 InvocationHanlder) 加上反射机制生成一个实现代理接口的匿名类,
在调用具体方法前调用 InvokeHandler 来处理。

创建 jdk 代理类

JDKStoreHandler.java(proxy):通过实现 InvocationHandler 接口的 invoke 方法,在里面进行反射调用,newProxyInstanse 通过目标对象创建真是对象。

public class JDKStoreHandler implements InvocationHandler {

    /**
     * 目标对象
     */
    private Object targetObject;

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if("operate".equals(method.getName())){System.out.println("收取管理费用 100 元");
        }
        return method.invoke(targetObject, args);
    }

    /**
     *
     * @param targetObject
     * @return
     */
    public Object newProxyInstanse(Object targetObject){
        this.targetObject = targetObject;
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),targetObject.getClass().getInterfaces(),this);
    }
}

JDK 代理对象调用

JDKDynamicConsumer.java(proxy): 通过 JDKStoreHandler 的 newProxyInstanse 创建真实目标对象,并调用接口的方法

public class JDKDynamicConsumer {public static void main(String[] args) {Store store = (Store)new JDKStoreHandler().newProxyInstanse(new PersonStore());
        store.operate();
        store.business();}
}

CGLIB 代理

cglib 动态代理是利用 asm 开源包,对代理对象类的 class 文件加载进来,通过修改其字节码生成子类来处理。

创建 cglib 代理对象

CglibProxy.java(proxy): 需要实现 MethodInterceptor 的 intercept 方法,并进行反射调用。通过 createProxyObject 创建真实对象,这里是根据目标对象直接生成对象。

public class CglibProxy implements MethodInterceptor{

    /**
     * CGlib 需要代理的目标对象
     */
    private Object targetObject;

    public Object createProxyObject(Object targetObject){
        this.targetObject = targetObject;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(targetObject.getClass());
        enhancer.setCallback(this);
        Object proxyObj = enhancer.create();
        return proxyObj;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {if("operate".equals(method.getName())){System.out.println("收取管理费用 100 元");
        }
        return method.invoke(targetObject, objects);
    }
}

CGLib 代理对象调用

CglibDynamicConsumer.java(client): 通过 CglibProxy 的 createProxyObject 创建真实目标对象,对进行方法调用

public class CglibDynamicConsumer {public static void main(String[] args) {Store store = (Store)new CglibProxy().createProxyObject(new PersonStore());
        store.operate();
        store.business();}
}

源码已上传:https://github.com/itrickzhan…

正文完
 0