尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

结构型模式-代理模式

结构型模式-代理模式 本文介绍了代理模式其他常见设计模式在本系列其他文章有兴趣可了解文章目录代理模式静态代理动态代理**JDK动态代理****CGLIB代理**总结代理模式静态代理举一个音乐会买票的例子感受一下静态代理定义一个售卖接口publicinterfaceSell{publicvoidsell();}定义音乐会售票类publicclassConcertSellimplementsSell{Overridepublicvoidsell(){System.out.println(卖票);}}定义中介类Java有自带的Proxy类最好不要使用Proxy作为类名在动态代理中我们会用到这个类中介增强了ConcertSell的功能publicclassProxyPointimplementsSell{privateConcertSellconcertSellnewConcertSell();Overridepublicvoidsell(){System.out.println(中介收取费用);concertSell.sell();}}运行publicclassClient{publicstaticvoidmain(String[]args){ProxyPointproxynewProxyPoint();proxy.sell();}}结果中介收取费用 卖票这里使用了接口使用接口比使用抽象父类耦合度低音乐会售票类和中介类都继承这个接口他们必须实现接口中的抽象方法中介类在实现的方法中使用了音乐会售票类的方法中介类在不影响音乐会售票类的同时增强了其功能动态代理JDK动态代理JDK动态代理只能代理接口中定义的方法换句话说目标类有接口才能用JDK动态代理JDK动态代理不是代理了目标类ConcertSell而是通过反射使用了目标类实例对象的方法准备好接口和目标类接口publicinterfaceSell{publicvoidsell();publicvoidsell2();}目标类publicclassConcertSellimplementsSell{Overridepublicvoidsell(){System.out.println(卖场次1票);}Overridepublicvoidsell2(){System.out.println(卖场次2票);}}我们直接使用工厂模式建一个ProxyFactory工厂将细节封装到这个工厂类中通过一个getProxy方法得到代理对象publicclassProxyFactory{privateConcertSellconcertSellnewConcertSell();/*执行newProxyInstance()方法时Java底层在内存中动态生成$Proxy0.class字节码 必须通过类加载器加载到JVM内存中才能成为一个可用的代理类 newProxyInstance()方法返回的是这个代理类的实例对象并由 proxy 变量接收。 *//*newProxyInstance()方法有三个参数 第一个参数是获取一个类加载器用来加载$Proxy0.class到JVM内存中, 第二个参数是获取目标类实现的接口数组(这就是JDK动态代理只能代理接口中定义的方法的原因) 第三个参数是匿名内部类形式其中有一个invoke方法(这里涉及到了反射)invoke方法三个参数分别是 Object proxy(代理对象自身), Method method(外部调用的接口方法), Object[] args(调用时传入的参数数组), method.invoke()利用了反射(这里的invoke方法和匿名内部类的invoke方法意义不同)调用了目标类实例对象的方法 在invoke方法里可以对目标类实例对象方法进行增强 */publicSellgetProxy(){//JDK动态代理代理的是接口中的方法强转类型自然是接口类型Sellproxy(Sell)Proxy.newProxyInstance(concertSell.getClass().getClassLoader(),concertSell.getClass().getInterfaces(),newInvocationHandler(){OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{//方法体System.out.println(中介收取费用);method.invoke(concertSell,args);returnnull;}});returnproxy;}}运行publicclassClient{publicstaticvoidmain(String[]args){ProxyFactoryfactorynewProxyFactory();Sellproxyfactory.getProxy();proxy.sell();proxy.sell2();}}结果中介收取费用 卖场次1票 中介收取费用 卖场次2票CGLIB代理CGLIB代理可以为没有实现接口的类提供代理CGLIB代理类是目标类的子类要求目标类可继承因此CGLIB代理不能代理final修饰的类CGLIB代理是第三方提供的包需引入对应jar包maven工程中可引入jar包坐标放在标签里dependencygroupIdcglib/groupIdartifactIdcglib/artifactIdversion3.3.0/version/dependencyjdk17报错可以将以上依赖替换为dependencygroupIdorg.springframework/groupIdartifactIdspring-core/artifactIdversion6.1.8/version/dependency同时包名也要替换// 原来是// import net.sf.cglib.proxy.Enhancer;// 现在改为importorg.springframework.cglib.proxy.Enhancer;其他包名同理将net.sf改为org.springframework报错原因有兴趣可自行搜索准备目标类ConcertSellpublicclassConcertSell{publicvoidsell(){System.out.println(卖场次1票);}publicvoidsell2(){System.out.println(卖场次2票);}}我们同样使用工厂模式建一个ProxyFactory工厂将细节封装到这个工厂类中通过一个getProxy方法得到代理对象publicclassProxyFactoryTimplementsMethodInterceptor{privatefinalClassTtargetClass;//创建ProxyFactory对象时将目标类字节码传递过来使ProxyFactory工厂成为一个通用工厂publicProxyFactory(ClassTtargetClass){this.targetClasstargetClass;}publicTgetProxy(){//创建工具类对象EnhancerenhancernewEnhancer();//告诉CGLIB要生成的代理类必须继承T(传过来的类型)enhancer.setSuperclass(targetClass);//设置回调函数当代理对象的方法被调用时会回调当前类的intercept方法//这里的参数要求必须是Callback接口的子类。而MethodInterceptor正是Callback最重要的子接口enhancer.setCallback(this);//返回代理对象并强转成目标类类型return(T)enhancer.create();}OverridepublicObjectintercept(Objecto,Methodmethod,Object[]objects,MethodProxymethodProxy)throwsThrowable{System.out.println(CGLIB中介收取费用);//可以使用method.invoke(o, objects)但这样就是利用反射调用方法了效率低//CGLIB的优势不是通过传统反射来调用父类方法而是通过动态生成的字节码直接调用类似invokevirtual指令性能远高于JDK原生反射ObjectresultmethodProxy.invokeSuper(o,objects);returnresult;}}运行publicclassClient{publicstaticvoidmain(String[]args){ProxyFactoryConcertSellproxyFactorynewProxyFactory(ConcertSell.class);ConcertSellproxyproxyFactory.getProxy();//代理对象的方法被调用时会回调intercept方法proxy.sell();proxy.sell2();}}结果CGLIB中介收取费用 卖场次1票CGLIB中介收取费用 卖场次2票总结以上就是本期要讲的内容本文介绍了代理模式其他常见设计模式在本系列其他文章有兴趣可了解
返回列表