结果显然是不行的,所以我需要去找宠物医生这些更专业的人来帮我的宠物治病。
这个时候,代理就出现了,而宠物医生就是代理,而我就是目标对象。
使用代理模式的条件
1、两个角色:执行者,被代理对象
3、执行者必须拿到被代理对象的个人资料
1.静态代理
代码实现:
/***我和宠物医生都是人,都有治疗技能,但是宠物医生比我更专业*/interfaceIPerson{voidtreat(Petpet);//治疗技能}/***宠物类*/classPet{privateStringname;publicPet(Stringname){this.name=name;}publicStringgetName(){returnname;}}/***目标对象实现”IPerson“接口*/classSelfimplementsIPerson{privatePetpet;publicSelf(Petpet){this.pet=pet;}publicvoidtreat(Petpet){System.out.println(pet.getName()+",你要多喝点水");}}/***代理对象与目标对象实现同一接口*/classPetDoctorimplementsIPerson{//接收目标对象privateIPersontargetObj;publicPetDoctor(IPersontargetObj){this.targetObj=targetObj;}@Overridepublicvoidtreat(Petpet){System.out.println("对"+pet.getName()+"进行检查");targetObj.treat(pet);System.out.println("对"+pet.getName()+"进行治疗");}}代码测试:
publicstaticvoidmain(String[]args){//我的宠物Petpet=newPet("多多");//目标对象IPersontarget=newSelf(pet);//代理对象IPersonproxy=newPetDoctor(target);proxy.treat(pet);}运行结果:
宠物医生对多多进行检查我对多多说,你要多喝点水宠物医生对多多进行治疗结果很明显,医生比我更专业,我只会让我的宠物喝水,但医生会先检查再进行专业的治疗,所以说代理是让更专业的对象帮你做事。
2.动态代理
动态代理又分为jdk动态代理和cglib动态代理,两者的区别是jdk动态代理的实现是基于接口,而cglib动态代理是基于继承,但两者做的是同一件事,那就是字节码重组。
基本流程都是根据目标对象的资料,通过反射获取该对象的信息,然后根据信息按照特定的写法重写一个java类,再进行编译并动态加载到JVM中运行,所以说动态代理在底层其实就是实现了字节码重组。
jdk动态代理实例演示
Person接口
//定义Person接口,技能是煮饭publicinterfacePerson{voidcook();}我自己,也就是被代理的对象,但我只会做可乐鸡翅
publicclassOneselfimplementsPerson{@Overridepublicvoidcook(){System.out.println("我会做可乐鸡翅");}}动态代理类,也是一个厨师,因为初始对于做菜比我更专业
publicclassKitchenerimplementsInvocationHandler{//需要代理的目标对象privateObjectobject;publicKitchener(Objectobject){this.object=object;}@OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{System.out.println("我会做糖醋排骨");method.invoke(object,args);//这是我会做的,其余两样是代理对象初始会做的System.out.println("我会做九转大肠");returnnull;}}测试代码
publicclassTestJdk{publicstaticvoidmain(String[]args){//创建目标代理对象Oneselfoneself=newOneself();InvocationHandlerkitchener=newKitchener(oneself);/**通过Proxy的newProxyInstance方法来创建我们的代理对象,做的就是字节码重组的工作,新生成一个java类在编译再加载到JVM运行*第一个参数是类加载器*第二个参数是我们这里为代理对象提供的接口,也就是代理对象所实现的接口,所以说在jdk动态代理中被代理对象需要实现一个接口*第三个参数handler,我们这里将这个代理对象关联到了上方的InvocationHandler这个对象上*/Personproxy=(Person)Proxy.newProxyInstance(kitchener.getClass().getClassLoader(),oneself.getClass().getInterfaces(),kitchener);System.out.println(proxy.getClass());//(1)proxy.cook();}}测试结果
classcom.sun.proxy.$Proxy0//(2)我会做糖醋排骨我会做可乐鸡翅我会做九转大肠可以看到(1)行代码打印出来的是一个代理类,而代理对象通过生成java类再编译加载运行对用户来说是无感知的,我们只知道返回回来的是一个代理对象,然后由代理对象去帮我们做事。
而cglib代理的实现原理也是一样的,只不过一个是基于接口,一个是基于继承,原理都是通过反射获取对象信息再根据对象信息创建java类编译加载运行,所以cglib暂时就不展开了,后期可以自己手写一个动态加深理解。
学习了动态代理后,在本人的工作中是没使用过的,但却是了解spring的AOP实现的必要基础,因为spring的AOP实现就是基于动态代理实现的。