代理模式

代理模式的定义:代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。

静态代理

静态代理是指预先确定了代理与被代理者的关系,在程序员运行之前,代理类.class文件就已经被创建了。
我们玩游戏经常遇见代打的情况,就用游戏的代打举例:
首先定义一个玩游戏的接口

package factory.proxy.staticproxy;

public interface IPlayGame {

    public void play();

    public void upGrade();
}

普通玩家玩游戏,实现玩游戏接口

package factory.proxy.staticproxy;

public class Player implements IPlayGame {
    @Override
    public void play() {
        System.out.println("玩游戏。。。");
    }

    @Override
    public void upGrade() {
        System.out.println("打怪升级。。。");
    }
}

代打玩游戏,要传入被代理人

package factory.proxy.staticproxy;

public class ProxyPlayer implements IPlayGame {

    IPlayGame player = null;

    public ProxyPlayer(IPlayGame player){
        this.player = player;
    }

    @Override
    public void play() {
        player.play();
    }

    @Override
    public void upGrade() {
        player.upGrade();
    }
}

客户端测试

package factory.proxy.staticproxy;

public class Client {

    public static void main(String[] args) {
        Player player = new Player();
        ProxyPlayer proxyPlayer = new ProxyPlayer(player);
        proxyPlayer.play();
        proxyPlayer.upGrade();
    }
}

代理模式可以有选择的在工作前后做一些必要的事情,比如我们代打游戏肯定收钱,那可以在代理类中加一个收钱的方法,放在代理方法中处理。

动态代理

动态代理本质上仍然是代理,情况与上面介绍的完全一样,只是代理与被代理人的关系是动态确定的,例如玩家平常没选代打,在玩游戏的时候才选代打,映射到编程领域为这个关系是在运行时确定的。

动态代理比起静态代理有什么好处呢?上面的静态代理例子中,如果要再换一个玩家的话,那就要重新创建玩家类与代理类了,扩展麻烦,不灵活,而用动态代理的话,那只要一个代打类即可,代打同时代打好几个玩家的号。

在java的动态代理机制中,有两个重要的类或接口,一个是InvocationHandler接口、另一个则是 Proxy类,这个类和接口是实现我们动态代理所必须用到的。

InvocationHandler接口是给动态代理类实现的,负责处理被代理对象的操作的,而Proxy是用来创建动态代理类实例对象的,因为只有得到了这个对象我们才能调用那些需要代理的方法。

用动态代理实现上述过程

  1. 构建一个打游戏接口
package factory.proxy.dynamicproxy;

public interface IPlayGame {

    public void play();

    public void upGrade();
}

  1. 玩家类
package factory.proxy.dynamicproxy;

public class Player implements IPlayGame {
    @Override
    public void play() {
        System.out.println("玩游戏。。。");
    }

    @Override
    public void upGrade() {
        System.out.println("升级。。。");
    }
}

  1. 构建一个动态代理类
package factory.proxy.dynamicproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class DynamicProxy implements InvocationHandler {

    private Object target;//被代理的对象

    public DynamicProxy(Object obj){
        this.target = obj;
    }

    public Object getProxy(){//获得当前代理
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object o, Method method, Object[] args) throws Throwable {
        System.out.println("当前进行到哪一步:" + method.getName());
        Object result=method.invoke(target,args);
        return result;
    }
}

  1. 客户端使用
package factory.proxy.dynamicproxy;

public class Client {

    public static void main(String[] args) {
        Player player = new Player();
        IPlayGame playGame = (IPlayGame) new DynamicProxy(player).getProxy();
        playGame.play();
        playGame.upGrade();
    }
}

结果:

"E:\IntelliJ IDEA 2019.3.3\jbr\bin\java.exe" "-javaagent:E:\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=13505:E:\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath D:\moyiworkspace\ACMPractise\bin factory.proxy.dynamicproxy.Client
当前进行到哪一步:play
玩游戏。。。
当前进行到哪一步:upGrade
升级。。。
JDK动态代理实现的原理

首先Jdk的动态代理实现方法是依赖于接口的,首先使用接口来定义好操作的规范。然后通过Proxy类产生的代理对象调用被代理对象的操作,而这个操作又被分发给InvocationHandler接口的 invoke方法具体执行

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;

此方法的参数含义如下
proxy:代表动态代理对象
method:代表正在执行的方法
args:代表当前执行方法传入的实参
返回值:表示当前执行方法的返回值

CGLIB代理

cglib是一个java字节码的生成工具,它动态生成一个被代理类的子类,子类重写被代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。

导入jar包
在这里插入图片描述

//被代理类
public class Product {
    public void getPrice(double d) {
        System.out.println("价格是:" + d);
    }
}
//代理
public class Client {
    public static void main(String[] args) {
        Product product = new Product();
        Product cglib = (Product) Enhancer.create(product.getClass(), new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                if("getPrice".equals(method.getName())) {//增强
                    objects[0] = (double) objects[0] * 0.8;
                }
                return method.invoke(product, objects);
            }
        });
        cglib.getPrice(1000);
    }
}

输出800.

常见的代理模式有以下几种类型:

远程(Remote)代理:为一个位于不同的地址空间的对象提供一个本地的代理对象,这个不同的地址空间可以是在同一台主机中,也可是在另一台主机中,远程代理又叫做大使(Ambassador)。

虚拟(Virtual)代理:如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。

Copy-on-Write代理:它是虚拟代理的一种,把复制(克隆)操作延迟到只有在客户端真正需要时才执行。一般来说,对象的深克隆是一个开销较大的操作,Copy-on-Write代理可以让这个操作延迟,只有对象被用到的时候才被克隆。

保护(Protect or Access)代理:控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限。

缓冲(Cache)代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。

防火墙(Firewall)代理:保护目标不让恶意用户接近。

同步化(Synchronization)代理:使几个用户能够同时使用一个对象而没有冲突。

智能引用(Smart Reference)代理:当一个对象被引用时,提供一些额外的操作,如将此对象被调用的次数记录下来等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值