从简入繁详解代理模式(手写JDK动态代理)

1 简单概要

代理模式:指为其他对象提供一种代理来控制对这个对象的访问。

 代理模式主要有两个目的:

①保护目标对象;

②增强目标对象。

它的类图如下:

2 分类与详解

2.1 静态代理

举个栗子:儿子正在找对象,而父母希望儿女早点找到另一半,于是在儿子找对象的同时帮他物色:

interface Person{
    void findLove();
}

public class Son implements Person {
    public void findLove() {
        System.out.println("儿子要求:是个女的");
    }
}

父亲帮找:

public class Father {
    private Son son;

    public Father(Son son){
        this.son = son;
    }

    public void findLove(){
        System.out.println("父亲帮找");
        this.son.findLove();
    }
}

Client类:

public class Client {
    public static void main(String[] args) {
        Father father = new Father(new Son());
        father.findLove();
    }
}

运行:

我们现在想让父亲帮表妹也找找,此时代码就需要修改Father类,不符合开闭原则,所以做如下优化:

public class Father {
    private Person person;

    public Father(Person person){
        this.person = person;
    }

    public void findLove(){
        System.out.println("父亲帮找");
        this.person.findLove();
    }
}

当Father中的Son替换为Person时,我们就可以代理所有实现了Person接口的类,表妹也是人,所以只需要增加一个表妹类,Client传参时传入new BiaoMei()就可以了,此时的代码对修改关闭,对扩展开放,符合开闭原则。

2.2 动态代理

如果父亲不仅要帮儿子找对象,也要帮很多人找对象,也就是媒婆,我们不可能创建上百个想表妹一样的类,所以有没有一种更加通用的解决方案呢?也许动态代理可以帮助我们。

2.2.1 JDK方式实现动态代理(手写JDK动态代理)

创建消费者类Customer(在媒婆处消费):

interface Person{
    void findLove();
}

public class Customer implements Person {
    public void findLove() {
        System.out.println("女的就行");
    }
}

创建媒婆类(Meipo):

public class Meipo implements InvocationHandler {
    //被代理的对象,保存起来方便invoke中的this.target的调用
    private Object target;

    public Object getInstance(Object target){
        this.target = target;
        Class<?> aClass = target.getClass();
        
        //创建代理类并返回
        return Proxy.newProxyInstance(aClass.getClassLoader(), aClass.getInterfaces(), this);
    }

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

    private void befor(){
        System.out.println("媒婆帮找");
    }

    private void after(){}
}

创建Client类:

public class Client {
    public static void main(String[] args) {
        Person person = (Person) new Meipo().getInstance(new Customer());
        person.findLove();
    }
}

运行:

那么动态代理是如何实现的呢?

她其实就是通过字节重组,重新生成对象来代替原始对象,以达到代理的目的。

字节码重组的基本步骤如下:

①获取被代理对象的引用,利用反射获取到它的所有接口;

②JDK动态代理类Proxy重新生成一个新的类,此类要实现刚才获取到的所有接口;

③动态生成新类的Java代码;

④编译.java文件成.class文件;

⑤加载编译好的.class文件。

 那么修改Client类,去查看一下生成好的.class文件:

public class Test {
    public static void main(String[] args) {
        try {
            Person person = (Person) new Meipo().getInstance(new Customer());
            person.findLove();
            byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Person.class});
            FileOutputStream fos = new FileOutputStream(new File("$Proxy0.class"));
            fos.write(bytes);
            fos.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

运行:

查看$Proxy0.class($开头的类是动态生成的):

public final class $Proxy0 extends Proxy implements Person {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    ......

    public final void findLove() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    ......

    static {
        try {
            m1 = Class.forName(
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值