JavaSE——代理

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaSE——代理相关的知识,希望对你有一定的参考价值。

声明:本栏目所使用的素材都是凯哥学堂VIP学员所写,学员有权匿名,对文章有最终解释权;凯哥学堂旨在促进VIP学员互相学习的基础上公开笔记。

代理

什么是代理?代理可以帮我们解决什么问题?

静态代理可以干的事情:

有时候我们有这样一种操作,我们去调用逻辑,但是逻辑方法内,我只写逻辑,不做其他事情。这个数据有效性验证我们不希望与逻辑混在一起。于是我们剥离开来。

当调用逻辑完毕后,我们还要判断逻辑是否正常完毕,如果抛出异常,还需要怎么操作。也就是我们需要在逻辑方法的前后做一些处理善后。

我们要在方法前后做事情。就需要调用逻辑的地方,先不调用逻辑,而是先调用数据有效性验证方法,验证完毕后去调用逻辑。或是调用完毕后再去调用逻辑。

调用逻辑后,在判断方法是否抛出异常,在进行善后操作。

这个操作,我们可以这样:

image

调用数据验证,调用逻辑。如果抛出异常,怎么处理。如果没有异常怎么处理。

这样就做到了,在方法前后前后做了操作。我们还可以使用静态代理操作。

静态代理做法:

image

申请接口,申请方法

image

对接口的实现。这是逻辑方法,我们需要在这个逻辑方法前后执行操作

image

写类继承与逻辑实现类

当看到这里,已经大概明白什么意思了。先执行操作,再调用父类的逻辑处理,调用处理完后,再执行操作。

image

很明显,这里就不能直实例化实现类,而是去调用实现类的子类。调用子类的server。

这就是静态代理的类代理,在方法的前后进行了操作。

静态代理的接口代理:

image

这里不再继承于类,而是实现与接口,重写接口的方法

image

现在的操作就是这样:实例化继承于接口代理类,在server方法中,完成预处理,拿获得的真正的server处理对象去调用逻辑,在做收尾操作。

静态代理的类代理是这样操作:调用server类的子类,由子类预处理,super调用父类逻辑,调用完毕后再收尾处理。

静态代理的接口代理是这样操作:调用类,由类预处理,获得server对象去调用server,调用完毕后再收尾处理。

类代理与接口代理是一致的,都是不直接调用处理类。由其他类或子类处理完后,在调用具体的处理类

动态代理解决的问题:

代理做到的操作是这样:比如我们要执行方法的日志追踪。我们需要在调用方法前,日志输出,再调用方法,结束前再做日志输出

为什么要方法日志追踪?当出问题时,可以根据日志分析。所以方法日志追踪还是很有必要的。

但是我们的方法上百上千,如果一一给每个方法做日志,那样首先考虑的问题是:这样的操作会不会太重复了。加上成百上千次日志。

这个操作可以由动态代理解决。

动态代理做法:

image

书写接口

image

实现接口,重写方法

image

实现InvocationHandler借口。Invocation翻译:调用。Handler翻译:处理。这是调用处理接口

这里有3个参数,一个proxy:真正的代理对象。Method触发代理时调用的方法,args方法的参数

处理什么调用呢?后面再看,这里还有一步操作是构造器要求对象,有什么用呢?待会再看

image

获得other接口的实现类的Class。Proxy.newProxyInstance生成动态代理类,需求参数:

实现的classloader实现类的加载器
实现类的接口
处理类

参数我们从class中获得再传入。这样就完成了代理。返回的对象转换为接口。当接口调用方法,会进入拦截器执行。

我们在处理类构造器中,要求参数obj,在这里我们将other对象传进去了。

查看方法invoke。当进入处理类,一律的请求都是发向invoke方法。此方法可以决定是否继续往后调用,像拦截器一样。

如果我们要往后调用,则拿获得的obj对象,method的invoke选择调用obj的这个方法

这个操作是这样的:接口调用方法,并不会进入实现类,而是进入处理类的invoke方法。这个方法可以决定是否继续往后调用。

这个方法上有method方法对象,这个方法对象,是接口调用的那个方法。是那个对象,如果我们要使用method继续往后调用。需要考虑一个问题。

调用method需要考虑的问题,这个method是调用哪个对象的?于是我们将other实现类传递过去,就是为了在这个时候,进行预处理后,method去调用获得的obj对象,就调用到处理类上了。调用完毕后,在做收尾工作。

关于方法的第一个参数与第二个参数,我的猜测是:

有一个实验是这样的:newProxyInstance得到的动态代理类,如果转换为other实现类报错,提示类不匹配,转换出错。如果转接口才会正常运行。

我的想法是:这里生成的动态代理类,是接口的实现类,与接口产生了关系。所以可以转换为接口,而转实现类是不可以的。

所以第二个参数,要求的是interferes,这里就传递了other实现类的接口,我觉得是为了让代理类实现于接口,接口在调用时,就是进入动态代理类。由代理类,转到第三个参数处理类上去。

但是获得代理类转换为接口,再获得的class,从interfaces得到的接口是class对象,但我这里的猜测是他与要代理的类的接口有关系

至于第一个参数类的加载器,没有拿捏的确认想法,但是他获得这个类加载器,应该是为了做一些配置而需要。

当把这三个参数ok后,动态代理就拿下了。第一个给它做参数的配置,第二个用来实现于接口,第三个是明确得到处理类。

届时一旦接口调用方法时,触发进入动态类,动态类转到处理类的invoke方法。如果要真实的调用到业务处理类上,处理类再获得业务处理类的对象,invoke方法上有method对象。如果method.invoke将对象传递,表示调用这个对象的这个method对象方法,则就调用到了业务实际处理类,在方法前后完成了预处理与善后操作。

这里动态代理的好处在那里呢?动态代理类不需要我们写,生成即可,进入处理类进行代理操作。

动态代理类的好处在于,代理类不需要我们写。我们直接在处理类中操作

我们于是就可以这样干,将处理类分出去,给其余要产生代理类的使用。这样他们产生代理类后,就会进入我们的处理类。

动态代理类与静态代理的区别这里:静态代理类需要自己写,不论是接口代理还是类代理。而动态代理是自己生成,届时我们只需要在处理类中操作即可。

如果我们要动态代理一个类,那么我们每次都需要newProxyInstance生成。每代理一个类都需要产生一个代理类。但处理类可以只写一份实例化多份分出去使用。但也可以写有多个。

这就是动态代理,其过程,并不会真正调用到处理类,是调用接口的方法时,会进入代理类,在转到处理类。要调用真正的处理类,还需要我们手动操作。在我们调用前后,可以由我们操作。动态代理,类不需要我们生成,调用接口进入代理类转到处理类,我们只需要关系一个处理类的操作即可。

代理又称切面,为什么叫切面?是这样的,我们本来的处理是执行的好好的,但我们要在执行的操作前与后执行操作。这就像切下去一样,本来的操作,横切一刀进行操作。所以叫切面。这是我的解释,很多名词都是与日常有联系的。

为什么不论是静态代理,还是动态代理,都是以接口来操作。都是面向接口来操作的。我们可以这样写的:

ServerIF ser=new xxx(); //接口
Server ser=new xxx(); //实现类

使用接口的目的也很好理解,接口可以不变,但类是需要变的,接口的变,无非是增加代码,类的类就可能会影响其余的地方。但是使用接口,其余地方使用调用,更换了接口的实现类,其余地方正常使用。但如果使用的是类,对类改变,比如更换类,更换子类,那么其余对类的地方也需要修改。这个时候就只能改源码了。而接口增加也是增加功能呢,不会影响其他地方调用。增加个子类,返回子类,无需改源码,功能就扩展。这就是我觉得的解耦与开闭原则的意思

这就是代理:

静态类代理:接口的内存地址是逻辑类的子类,接口调用方法,转到子类,子类处理转父类

静态接口代理:接口的内存地址是接口的实现类,接口调用转到实现类,实现类拿逻辑类的对象调用逻辑类

两种代理,都是不调用逻辑类,转发过去调用。只是两种方式不同。

动态代理:代理类不需要我们写,我们只需要关系处理类。

猜测:代理类实现于接口,接口调用时,转到代理类,处理类再转到处理类。我们在处理类中操作。处理类如果要调用逻辑类,需要处理类获得逻辑类对象,去调用。

动态代理类,有点像静态代理的接口代理,负责帮我们拦截,但真正要操作过去,还需要获得逻辑类对象去操作

这就是代理,在方法的前与后可以进行操作。这种横切一刀插入的操作,又称切面编程。

以上是关于JavaSE——代理的主要内容,如果未能解决你的问题,请参考以下文章

JavaSE——代理

##(⊙o⊙)值得收藏的JavaSE万字进阶版(⊙o⊙)##JavaSE 高级反射-动态代理-设计模式-JVM篇

JavaSE8基础 Proxy 对接口进行动态代理 简单示例

JavaSE-day15

javase 和javaee的区别?

Java探针技术-JVM的动态agent机制:在main函数启动之后运行agent