在这几块代码中实现了一个对买衣服这一行为的动态代理,当创建好代理类的时候能够通过对代理类的创建,传入想要购买的衣服的尺码,从而实现代理的整个流程。
首先创建了一个BuyClothes接口,其中包含着方法clothes(需要传入的参数为尺码大小size)。
然后又一个衣服工厂的类ClothesFactory,实现了这个接口并重写了接口中的方法
这时创建了一个代理类,这个代理类也实现了BuyClothes接口,这个类的内部,创建了刚才的那个衣服工厂类ClothesFactory,相当于把这个衣服工厂类注入到了衣服代理类中。
然后在这个代理类中,定义了两个方法,一个代表的就是代理售前服务,一个代表的是代理售后服务。因为他实现了实现了BuyClothes接口,所以也要对clothes方法进行重写,传入的参数也是size。
其实这个代理类就相当于在原先ClothesFactory类的方法上做了一个增强,不仅完成了原先类的方法,还添加了一些自己自定义的东西(也就是写的那个售前和售后服务)
最后在测试类中,把自己看做一个客户,比如说客户找代购的时候,它只需要告诉代购自己要买一件什么样的衣服,而哪个工厂生成衣服其实他并不关心,所以只需要传入衣服的尺码,就能得到整个代理执行的过程。
跟示例一差不多,也是先有一个接口——Singer
这时候有一个Cai的接口实现了这个Singer类。肯定就得重写它的两个方法啊
此时也出现了一个代理类(也需要实现最开始的那个接口),他需要对这个叫做Cai的类中的singing和dance方法都做一个增强,成为一个完整的过程。
最后就是编写实例进行测试了,可以直接去new一个代理类,然后用这个接口类型去指向它(多态)。此时的这个叫做singer的对象,直接调用唱歌和跳舞方法的时候,就可以得到增强后的输出结果。
这种静态的代理算是实现完成了,但是思考一下,这种代理的模式写的太死了,每有一个类,就要创建一种代理,要是全按照静态代理来写的话,那么终究会导致内存爆炸这样一个后果。所以我们要能动态的根据传入的需要代理的类,增加上增强的逻辑,实现能够代理所有的这么一个效果。
还是跟刚才一样有一个singer接口,里面有两个方法dance()和singing()
也是有Cai这样一个类
此时我们要实现的是,无论传输的是什么样的类,什么样的接口,什么样的规则,我们都能够将这个增强后的方法给调出来
此时有这样一个类——也就是动态代理的类(里面写着动态代理实现的规则)
既然要实现动态代理,这个动态代理类一定要实现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()
方法中,需要传入以下三个参数:
ClassLoader loader
: 类加载器,用于加载代理类的字节码。
Class>[] interfaces
: 一个接口数组,指定被代理类所实现的接口。
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类,再调用方法的时候,也就执行的是增强后的方法了。
首先是有这样一个类Singer(刚才的Singer是接口)
然后有一个子类——SingerSub,它是在原来的Singer类的基础上重写Singer的两个方法(就是用Super关键字直接调用了父类的同名方法,在此基础上写出自己增强后的逻辑)
此时测试,也能够实现类似效果
运行结果