java中的代理机制(宝宝巴士版)

静态代理

示例一

java中的代理机制(宝宝巴士版)_第1张图片

         在这几块代码中实现了一个对买衣服这一行为的动态代理,当创建好代理类的时候能够通过对代理类的创建,传入想要购买的衣服的尺码,从而实现代理的整个流程。

        首先创建了一个BuyClothes接口,其中包含着方法clothes(需要传入的参数为尺码大小size)。

        然后又一个衣服工厂的类ClothesFactory,实现了这个接口并重写了接口中的方法

        这时创建了一个代理类,这个代理类也实现了BuyClothes接口,这个类的内部,创建了刚才的那个衣服工厂类ClothesFactory,相当于把这个衣服工厂类注入到了衣服代理类中。

        然后在这个代理类中,定义了两个方法,一个代表的就是代理售前服务,一个代表的是代理售后服务。因为他实现了实现了BuyClothes接口,所以也要对clothes方法进行重写,传入的参数也是size。

        其实这个代理类就相当于在原先ClothesFactory类的方法上做了一个增强,不仅完成了原先类的方法,还添加了一些自己自定义的东西(也就是写的那个售前和售后服务)

        最后在测试类中,把自己看做一个客户,比如说客户找代购的时候,它只需要告诉代购自己要买一件什么样的衣服,而哪个工厂生成衣服其实他并不关心,所以只需要传入衣服的尺码,就能得到整个代理执行的过程。

示例2

 跟示例一差不多,也是先有一个接口——Singer

java中的代理机制(宝宝巴士版)_第2张图片

这时候有一个Cai的接口实现了这个Singer类。肯定就得重写它的两个方法啊

java中的代理机制(宝宝巴士版)_第3张图片

         此时也出现了一个代理类(也需要实现最开始的那个接口),他需要对这个叫做Cai的类中的singing和dance方法都做一个增强,成为一个完整的过程。

java中的代理机制(宝宝巴士版)_第4张图片

 最后就是编写实例进行测试了,可以直接去new一个代理类,然后用这个接口类型去指向它(多态)。此时的这个叫做singer的对象,直接调用唱歌和跳舞方法的时候,就可以得到增强后的输出结果。

java中的代理机制(宝宝巴士版)_第5张图片

        这种静态的代理算是实现完成了,但是思考一下,这种代理的模式写的太死了,每有一个类,就要创建一种代理,要是全按照静态代理来写的话,那么终究会导致内存爆炸这样一个后果。所以我们要能动态的根据传入的需要代理的类,增加上增强的逻辑,实现能够代理所有的这么一个效果。

 

动态代理

JDK代理

还是跟刚才一样有一个singer接口,里面有两个方法dance()和singing()

java中的代理机制(宝宝巴士版)_第6张图片

 也是有Cai这样一个类

java中的代理机制(宝宝巴士版)_第7张图片

 此时我们要实现的是,无论传输的是什么样的类,什么样的接口,什么样的规则,我们都能够将这个增强后的方法给调出来

此时有这样一个类——也就是动态代理的类(里面写着动态代理实现的规则)

既然要实现动态代理,这个动态代理类一定要实现InvocationHandler接口

class Ruler implements InvocationHandler{
    private Singer s;

    public Ruler(Singer s) {
        this.s = s;
    }

    @Override
    public Object invoke(Object p, Method method, Object[] args) throws Throwable {
//        System.out.println(p.getClass().toString());
        System.out.println("先收钱");
        Object returnVal = method.invoke(s, args);
        System.out.println("asdfasdf");
        return returnVal;
    }
}
Object returnVal = method.invoke(s, args);

        method.invoke(s, args);——代表被代理的那个类(Cai),未经增强的方法,并且用一个Object类型的returnVal接收,确保这个代理类所返回的类型与被代理类的返回类型一致。

        其他的就是像之前一样,在代理里中写一些增强的逻辑了

        但是这里需要注意的是:与静态代理不同,这里注入的不是需要被代理的类,而直接注入的是这个接口

        

再来看测试类

public class Test {
    public static void main(String[] args) {
        Cai cai =new Cai();
        Ruler ruler = new Ruler(cai);
        //构建了 以原被代理类为基准的代理类的一个对象

        Object o = Proxy.newProxyInstance(Cai.class.getClassLoader(), new  Class[]{Singer.class}, ruler);
        System.err.println(o.getClass().toString());
        System.out.println(Arrays.toString(o.getClass().getInterfaces()));
        if(o instanceof Singer){
            Singer singer =  (Singer)o;
            singer.dance();
            singer.singing();
            singer.toString();
        }
    }
}

首先还是创建了Cai的对象,然后把这个对象传进了代理规则当中

Cai cai =new Cai();
Ruler ruler = new Ruler(cai);
//构建了 以原被代理类为基准的代理类的一个对象

此时就引入了JDK Proxy中的newProxyInstance(创建一个代理实例)方法

Object o = Proxy.newProxyInstance(Cai.class.getClassLoader(), new  Class[]{Singer.class}, ruler);

Proxy.newProxyInstance() 方法中,需要传入以下三个参数:

  1. ClassLoader loader: 类加载器,用于加载代理类的字节码。

  2. Class[] interfaces: 一个接口数组,指定被代理类所实现的接口。

  3. InvocationHandler h: 一个实现了 InvocationHandler 接口的对象,用于处理代理对象方法的调用。

newProxyInstance() 方法中,并不直接将被代理类和其实现的方法传给代理类。而是通过指定被代理类所实现的接口(interfaces 参数)来确定代理类的行为。

if(o instanceof Singer){
    Singer singer =  (Singer)o;
    singer.dance();
    singer.singing();
    singer.toString();
}

然后就是检查代理对象 o 是否属于 Singer 类(或其子类)的实例。如果满足条件,则将 o 强制转换为 Singer 类型,并调用 Singer 类的 dance()singing()toString() 方法。

此时的o对象转换为Singer类,再调用方法的时候,也就执行的是增强后的方法了。

Cglib代理思想

首先是有这样一个类Singer(刚才的Singer是接口)

java中的代理机制(宝宝巴士版)_第8张图片

 然后有一个子类——SingerSub,它是在原来的Singer类的基础上重写Singer的两个方法(就是用Super关键字直接调用了父类的同名方法,在此基础上写出自己增强后的逻辑

java中的代理机制(宝宝巴士版)_第9张图片

 此时测试,也能够实现类似效果

java中的代理机制(宝宝巴士版)_第10张图片

 运行结果

java中的代理机制(宝宝巴士版)_第11张图片

 

你可能感兴趣的:(java,开发语言)