代理模式简单的使用和分析

代理模式

代理模式分为静态代理和动态代理,核心的功能就是方法增强。

通过代理可以在不修改原有的代码的情况下拓展该方法。由代理对象去调用目标对象。

1. 静态代理

静态代理角色分析

  • 抽象角色: 一般使用接口或者抽象类来实现
  • 真实角色: 目标对象,被代理的角色
  • 代理角色: 代理真实角色;代理真实角色后,还可以增加一些真实角色的操作
  • 客户: 使用代理角色去实现一些操作
代码实现

抽象角色

public interface BuyHouse {

    void buyHouse();
}

真实角色

public class BuyHouseImpl implements BuyHouse {

    @Override
    public void buyHouse() {
        System.out.println("我要买房");
    }
}

代理角色

public class BuyHouseProxy implements BuyHouse {

    //代理需要持有被代理的对象
    private BuyHouse buyHouse;

    public BuyHouseProxy(BuyHouse buyHouse){
        this.buyHouse = buyHouse;
    }

    @Override
    public void buyHouse() {
        //在不改变真实对象的前提下增加功能
        System.out.println("买房前准备");
        //调用真实对象的方法
        buyHouse.buyHouse();
        System.out.println("买房后装修");
    }
}

客户

public class ProxyTest {
    public static void main(String[] args) {
        BuyHouse buyHouse = new BuyHouseImpl();
        buyHouse.buyHouse();
        System.out.println("============================");
        BuyHouseProxy proxy = new BuyHouseProxy(buyHouse);
        proxy.buyHouse();
    }
}

结果

我要买房
============================
买房前准备
我要买房
买房后装修
静态代理总结

​ 优点:符合开闭原则,不改变真实对象的结构,对目标对象进行了功能的拓展。

​ 缺点:如果需要代理多个真实对象,工作量大,不宜管理。同时如果接口发生了变化,代理类也需要修改。

tips:开闭原则–>软件实现应该对扩展开放,对修改关闭

2.动态代理

在动态代理中我们不需要再手动创建代理类,代理对象的创建由JDK在运行时为我们动态的创建。

2.1 JDK原生的动态代理

JDK的动态代理需要了解两个类

核心:InvocationHandlerProxy

【InvocationHandler:调用处理程序】

源码

public Object invoke(Object proxy, Method method, Object[] args);
//参数
//proxy - 调用该方法的代理实例
//method - 所属方法对应于调用代理实例上的接口方法的实例,方法对象的声明类将是该方法声明的接口
//args - 包含的方法调用传递代理实例的参数值的对象的阵列,或null如果接口方法没有参数,

【Proxy: 代理】

接口返回指定接口的代理类实例,该接口将方法调用分派给指定的调用处理程序。

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
    
  // ClassLoader : the class loader to define the proxy class 定义代理类的类加载器
  // interfaces 代理类要实现的接口列表
  // InvocationHandler 指定动态处理器,执行目标对象的方法时,会触发事件处理器的方法

代码实现

依然是刚才的例子,改用动态代理。只修改了BuyHouseProxy这个类

代理对象

public class BuyHouseProxy implements InvocationHandler {

    //被代理对象
    private Object object;

    public BuyHouseProxy(Object object){
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("看房");
        System.out.print("执行方法method:");
        Object invoke = method.invoke(object,args);
        System.out.println("装修");
        return invoke;
    }
}

客户

public class ProxyTest {
    public static void main(String[] args) {

        BuyHouse proxyBuy = new BuyHouseImpl();

     //新建一个代理实例
       BuyHouse buyHouse =(BuyHouse)Proxy.newProxyInstance(proxyBuy.getClass().getClassLoader(),
               proxyBuy.getClass().getInterfaces(),new BuyHouseProxy(proxyBuy));

        buyHouse.buyHouse();
    }
2.2 CGLib实现动态代理

JDK实现动态代理需要真实对象通过接口定义方法,对于没有接口的类,我们可以使用CGLib。其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。

实现CGLib动态代理

让代理接口继承MethodInterceptor(方法拦截器)并实现intercept方法:拦截所有目标方法的调用

 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
     //obj : 目标类的实例
     //method : 目标类方法的反射
     //args: 方法的动态入参
     //proxy: 代理类实例

贴代码!

代理对象

public class BuyHouseProxy implements MethodInterceptor{

    private Object object;

    public Object getInstance(final Object object){
        this.object = object;
        //使用Enhancer创建代理类
        Enhancer enhancer = new Enhancer();
        //继承被代理类
        enhancer.setSuperclass(this.object.getClass());
        //设置回调
        enhancer.setCallback(this);
        //生成代理对象并返回
        return enhancer.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("看房");
        Object result = proxy.invokeSuper(object, args);
        System.out.println("装修");
        return result;
    }
}

BuyHouseProxy类就相当于A类,而Enhancer类则是B类,A类中调用了Enhancer类的setCallback(this)方法,并将回调对象this作为实参传递给了Enhancer类,Enhancer类在后续执行过程中,会调用A类中的intercept()方法。这个intercept()就是回调方法 。

public static void main(String[] args) {

        BuyHouseProxy cglibProxy = new BuyHouseProxy();
        BuyHouseImpl instance = (BuyHouseImpl) cglibProxy.getInstance(new BuyHouseImpl()); //生成代理对象
        instance.buyHouse();  //调用的是intercept()方法
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值