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

深入设计模式-代理模式

时间:2023-04-01 17:56:28 Java

1.代理模式介绍2.代理模式代码演示3.总结1.代理模式定义介绍:1)代理模式提供了代理对象的替代品来控制访问tothisobject,就是通过代理对象来访问该对象。这样做的好处是可以在目标物体的基础上增加额外的增强操作。2)被代理对象可以是远程对象,创建成本高的字段和需要安全控制的字段3)代理方式有静态代理、动态代理、cglib代理三种不同形式。说明:代理最著名的使用场景就是大家熟知的AOP。就拿我们非常熟悉的事务注解@Transactional来说吧。我们知道,加上这个注解后,函数方法就会变成事务操作。我们都知道,在用sql写事务的时候,如果要进行事务操作,需要写两条这样的sql语句:starttransaction;//中间执行业务逻辑commit;这时候我们已经把中间的业务逻辑写好了,加上注解之后,就相当于把这个对象交给了一个代理对象,让代理对象去执行开启和关闭事务的逻辑。我们只需要编写业务逻辑。同时,该方法也得到了增强,有前后方法,有交易效果,增强了额外的功能操作。2、根据代理模式使用代码进行演示1)静态代理基本介绍静态代理模式:使用静态代理时,需要定义一个接口或者一个父类,以及代理对象(目标对象)和代理对象实现一个公共接口或继承自同一个父类。具体要求1)定义一个接口ITeacherDao2)目标对象TeacherDAO实现了接口ITeacherDAO3)定义一个代理对象TeacherProxy,它也实现了ITeacherDao4)调用时通过调用代理对象的方法调用目标对象5)代理对象和目标必须实现相同的接口,然后通过调用相同的方法来调用目标对象的方法。代码展示ITeacherDao:publicinterfaceITeacherDao{voidteach();//教学方法}TeacherDao:publicclassTeacherDaoimplementsITeacherDao{@Overridepublicvoidteach(){System.out.println("老师开始上课了!");}}TeacherProxy:publicclassTeacherProxyimplementsITeacherDao{//先传入要代理的对象privateITeacherDaotarget=newTeacherDao();publicTeacherProxy(ITeacherDaotarget){this.target=target;}//执行代理方法,在Enhance方法前后@Overridepublicvoidteach(){System.out.println("Agentstarts");target.teach();System.out.println("代理结束");}}publicstaticvoidmain(String[]args){//代理对象ITeacherDaoiTeacherDao=newTeacherDao();//代理对象TeacherProxyteacherProxy=newTeacherProxy(iTeacherDao);//执行代理对象的方法teacherProxy.teach();}优点:符合开闭原则,可以扩展目标对象。缺点:需要为每个需要增强的服务创建一个类,容易形成类爆炸。2)动态代理动态代理的基本介绍:1)代理对象不需要实现接口,但目标对象必须实现接口,否则不能使用2)代理对象的生成是使用jdk在内存中动态构建代理对象的API3)动态代理又称:jdk代理,接口代理代码实现:{@Overridepublicvoidteach(){System.out.println("老师开始上课了!");}}ProxyFactory:publicclassProxyFactory{//维护一个目标对象privateObjecttarget;//创建一个构造函数来初始化一个目标对象publicProxyFactory(Objecttarget){this.target=target;}publicObjectgetProxyInstance(){//当前对象使用的目标类加载器ClassLoaderclassLoader=target.getClass().getClassLoader();//目标对象实现的接口类型,由泛型确认TypeClass[]classes=target.getClass().getInterfaces();//当执行到目标对象的方法时,会触发事件处理方法,并将当前执行的对象作为参数传递给InvocationHandlerinvocationHandler=null;returnProxy.newProxyInstance(classLoader,classes,newInvocationHandler(){@OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{//增强逻辑System.out.println("JDKproxystart");//原方法执行逻辑,执行后返回值Objectinvoke=method.invoke(target,args);System.out.println("JDK代理端");返回调用;}});}}注意,Proxy.newProxyInstance()方法有三个参数,Proxy.newProxyInstance()方法接受三个参数:ClassLoaderloader:指定当前目标对象使用的类加载器。获取loader的方法是固定的。Class[]interfaces:指定目标对象实现的接口类型,使用泛型方法确认类型。InvocationHandler:指定动态处理在执行目标对象的方法时,只需要按照上面的注释传入会触发事件处理器的方法即可,用法也很简单优点:动态代理大大减少了我们的开发任务,同时减少业务接口依赖。缺点:仍然无法摆脱接口代理的束缚,无法实现类的动态代理。3)cglib代理1)需要引入cglib依赖2)通过字节码技术为一个类创建子类,使用方法拦截技术拦截子类中所有父类方法调用,将横切逻辑编织到其中。代码展示:TeacherDao:publicclassTeacherDao{publicvoidteach(){System.out.println("老师开始上课了!");}}CglibProxyFactory:publicclassCglibProxyFactoryimplementsMethodInterceptor{//待增强的目标类privateObjecttarget;publicCglibProxyFactory(Objecttarget){this.target=target;}publicObjectgetProxyInstance(){//创建工具类Enhancerenhancer=newEnhancer();//设置父类enhancer.setSuperclass(target.getClass());//设置回调函数enhancer.setCallback(this);//创建子类对象,即代理对象returnenhancer.create();}//重写拦截,会调用目标对象的方法@OverridepublicObjectintercept(Objectobj,Methodmethod,Object[]args,MethodProxymethodProxy)throwsThrowable{//增强逻辑System.out.println("cglib开始”);//执行后返回的参数Objectinvoke=methodProxy.invokeSuper(obj,args);//增强逻辑System.out.println("cglibend");//返回参数returninvoke;}}publicstaticvoidmain(String[]args){//目标代理对象TeacherDaotarget=newTeacherDao();//代理工厂CglibProxyFactorycglibProxyFactory=newCglibProxyFactory(target);//从代理工厂返回代理对象TeacherDaoproxyInstance=(TeacherDao)cglibProxyFactory.getProxyInstance();//执行代理对象的方法proxyInstance.teach();}优点:可以增强类,CGLIB创建的动态代理对象比JDK创建的动态代理对象性能更高缺点:CGLIB创建代理对象的时间比JDK多很多,编码也不是很方便的。同时,由于CGLib使用了动态创建子类的方法,所以不能代理最终修改的方法。3.总结代理模式是spring底层AOP的实现方式。目的是在业务逻辑代码中切入一些增强,统一管理这方面。