当前位置: 首页 > 后端技术 > Java

代理方式

时间:2023-04-01 14:35:18 Java

目录静态代理动态代理JDK动态代理cglib动态代理静态代理类和代理类都实现了苹果接口publicinterfaceApple{IntegerbuyApple();}创建一个“烟台”苹果实例作为代理类,其中主要实现了一个买苹果的方法,也是后面主要用来做代理增强的方法。publicclassYanTaiApple实现Apple{privateIntegerprice;publicYanTaiApple(Integerprice){this.price=price;}@OverridepublicIntegerbuyApple(){returnthis.price;}}为“烟台”苹果创建一个代理类,其主要充当中间人,主要提升价格。publicclassYanTaiAppleProxy实现Apple{privateAppleapple;publicYanTaiAppleProxy(Appleapple){this.apple=apple;}@OverridepublicIntegerbuyApple(){整数价格=apple.buyApple()+2;System.out.println("苹果进货价"+apple.buyApple()+"元,售价"+price+"元");退货价格;}}在下面的方法中,我们通过代理购买苹果...publicclassStaticProxyTest{@Testpublicvoidtest(){Appleapple=newYanTaiAppleProxy(newYanTaiApple(3));苹果.buyApple();}}======结果======苹果进价3元,售价5元动态代理仔细分析上面的静态代理,我们会发现要代理每个类,我们必须创建一个不同的代理类,如果有河南苹果、新疆苹果、昭通苹果……那么我们需要为每一种苹果创建一个代理类,难道不能用一个代理来代表多种苹果吗?显然,静态代理有很大的局限性。动态代理就是通过反射动态创建原类的代理类,然后在系统中用代理类替换原类。在java语言中,动态代理主要是通过反射机制来实现的。JDK动态代理jdk动态代理主要是基于接口和java反射包中的Proxy类实现的,即代理类和代理类实现相同的接口,然后通过Proxy代理接口动态扩展(emm....主要看下面的实现)。接口和原类我们继续使用上面的Apple和YanTaiApple,然后代理类实现如下,我们需要实现接口InvocationHandler然后在invoke方法中增强方法调用(代理的价格增加了二元),当原类与this代理类关联后,执行接口的方法会自动进入invoke方法进行增强。公共类AppleProxyHandler实现InvocationHandler{privateAppleapple;publicAppleProxyHandler(Appleapple){this.apple=apple;}@OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{//获取价格字段Fieldfield=apple.getClass().getDeclaredField("price");//释放权限-forprivatefield.setAccessible(true);整数price=(Integer)field.get(apple);//重置值字段。设置(苹果,价格+2);返回方法。调用(苹果,参数);}}通过Proxy关联YanTaiApple和AppleProxyHandler实例。当然,AppleProxyHandler的构造参数不仅可以传入YanTaiApple实例,还可以传入其他实现Apple接口的类的实例,也就是说AppleProxyHandler可以代理所有Apple接口的实现类。publicclassJdkProxyTest{@Testpublicvoidtest(){//关联苹果apple=(Apple)Proxy.newProxyInstance(this.getClass().getClassLoader(),newClass[]{Apple.class},newAppleProxyHandler(newYanTaiApple(2)));System.out.println(apple.buyApple());}}=====Result=====4仔细考虑上面的设计有点不合理,因为Apple接口可能不仅有buyApple方法还有其他方法,所以我们的代理类显然要代理buyApple方法,所以我们可以做以下优化。publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{if("buyApple".equals(method.getName())){//获取价格字段Fieldfield=apple.getClass().getDeclaredField(“价格”);//释放权限-forprivatefield.setAccessible(true);整数price=(Integer)field.get(apple);//重置值field.set(apple,price+2);}returnmethod.invoke(apple,args);}cglib动态代理cglib代理和jdk代理的主要区别是jdk动态代理只支持接口代理不支持类代理,只能传Proxy.newProxyInstance的第二个参数到接口Object集合的类,如果传入类,会报java.lang.IllegalArgumentException:java.lang.Objectisnotaninterface异常。而cglib是通过继承来实现动态代理的,在运行时会动态生成一个代理类的子类对象,所以如果这个类被final修饰,就无法被cglib代理。我们继续用苹果的例子,但是使用cglib动态代理,我们不需要统一的接口类。publicclassYanTaiApple{publicIntegerprice;publicYanTaiApple(Integerprice){this.price=price;}publicIntegerbuyApple(){returnthis.price;}}代理类实现MethodInterceptor接口,然后在拦截方法中实现代理逻辑publicclassAppleProxyimplementsMethodInterceptor{@OverridepublicObjectintercept(Objectapple,Methodmethod,Object[]objects,MethodProxymethodProxy)throwsThrowable{//apple是YanTaiApple动态生成的子类Fieldfield=apple.getClass()。getSuperclass().getDeclaredField("价格");field.setAccessible(true);整数price=(Integer)field.get(apple);field.set(苹果,价格+2);返回方法Proxy.invokeSuper(苹果,对象);}}测试类需要使用Enhancer类,设置代理类为SuperClass,代理类为CallbackpublicclassCglibProxyTest{@Testpublicvoidtest(){Enhancerenhancer=newEnhancer();enhancer.setSuperclass(烟台苹果.class);enhancer.setCallback(新A苹果代理());//参数类型,参数值-create相当于构造函数YanTaiAppleyanTaiApple=(YanTaiApple)enhancer.create(newClass[]{Integer.class},newInteger[]{3});System.out.println(yanTaiApple.buyApple());}}=====结果=====5