1.署理模式的作用
能通过署理对象间接实现对目的对象的访问,在不改变源代码的情况下对目的对象的方法进行增强。
什么是通过署理对象间接实现对目的对象的访问?
举个生存中的例子:例如你买车是通过4s店(署理对象),而不是直接去车工厂(目的对象),你只需访问4s店。
那什么不改变源代码的情况下对目的对象的方法进行增强?
还是4s店和车工厂的例子:
你去4s店买车,4s店除了卖车给你,它还有一系列的服务,例如:推荐保险,上车牌等等;
但是你去工厂就只能买车,没有其他的附加服务;也就是说4s店(署理对象)在车工厂(目的对象)的卖车底子上进行了一系列增强,但是车厂还是一样的卖车,并没有被改变。
2.署理模式的分类
署理模式分为静态署理和动态署理。
2.1静态署理
2.1.1静态署理的实现
实现步调
1.署理类与目的类实现同一接口
2.署理对象有目的对象的引用,在同名方法中调用目的对象的方法,并在前后根据需求进行增强。
实现代码
接口代码
- public interface AInterface {
- void say();
- }
复制代码 目的类代码
- public class AInterfaceImpl implements AInterface{
- @Override
- public void rap() {
- System.out.println("rap");
- }
- @Override
- public void basketball() {
- System.out.println("篮球");
- }
- }
复制代码 署理类代码
- public class AStaticProxy implements AInterface{
- //目标对象
- private AInterface aInterface;
- //注入目标对象
- public AStaticProxy(AInterface aInterface) {
- this.aInterface = aInterface;
- }
- @Override
- public void rap() {
- System.out.println("前置增强");
- aInterface.rap();
- System.out.println("后置增强");
- }
- @Override
- public void basketball() {
- System.out.println("前置增强");
- aInterface.basketball();
- System.out.println("后置增强");
- }
- }
复制代码 2.2.1静态署理的缺点
1.只能署理某一类接口
2.若进行多次增强,大概署理类暴增
3.修改接口,要同时维护目的类和署理类
4.如果署理类的增强逻辑一致,大概造成大量重复代码
5.增强代码和目的方法硬编码
2.2动态署理
针对静态署理的缺点,我们大概观察到,很多静态署理的缺点都来自于署理类;
如果我们将署理类干掉,就能解决静态署理的大部门缺点。
可是在静态署理中我们通过署理类的构造方法才能得到署理对象,如果没有署理类,怎么创建署理对象呢?
我们先观察一下到底静态署理是怎样通过署理类得到署理对象的,这就涉及到java代码的运行原理了。
编译 类加载 反射得到构造方法
署理类-------> 署理类.class----------> JVM中的Class------------------------>创建得到署理对象
那么动态署理没有署理类,只能通过接口.class,很明显会在得到构造方法这里卡住,因为接口没有构造方法。
那么有没有办法可以或许既有接口的方法信息又有构造方法呢?
答案是:通过Proxy类的getProxyClass(classLoader,Interface)方法,我们只需传入将接口的信息作为参数传入,就能得到一个既有接口信息又有构造方法的Class对象,通过该Class得到构造方法,我们就能创建署理对象了。
那为什么Proxy类的getProxyClass方法那么神奇?
这里尚且不做深入了解,你可以理解为它就是 想办法把接口Class内里的方法信息拼接一个构造方法得到新的Class。
2.2.1动态署理的实现
实现步调
1.编写一个工具类,内里提供一个静态方法getProxy(Object target,InvocationHandler i)
2.在getProxy()方法中,通过Proxy类的静态方法getProxyClass(classLoader,Interface),传入目的对象接口的参数,然后得到新的署理Class对象
3.通过署理Class对象调用getDeclaredConstructor(InvocationHandler.class)方法,传入Invocationhandler的Class对象得到构造方法对象
4.通过构造方法对象的newInstance(InvocationHandler)传入Invocationhandler对象创建得到署理对象
实现代码
接口代码
- public interface AInterface {
- void say();
- }
复制代码 目的类代码
- public class AInterfaceImpl implements AInterface{
- @Override
- public void rap() {
- System.out.println("rap");
- }
- @Override
- public void basketball() {
- System.out.println("篮球");
- }
- }
复制代码 署理工具类的代码
- public class MyProxy {
- /**
- * 获取代理对象
- * @param target 目标对象
- * @param invocationHandler 代理处理器
- * @return
- * @throws Exception
- */
- public static Object getProxy(Object target, InvocationHandler invocationHandler) throws Exception{
- //获得目标对象的Class对象
- Class clazz = target.getClass();
- //根据目标对象的Class对象得到代理对象的Class
- Class proxyClass = Proxy.getProxyClass(clazz.getClassLoader(), clazz.getInterfaces());
- //根据代理对象Class获得代理对象的构造器
- Constructor declaredConstructor = proxyClass.getDeclaredConstructor(InvocationHandler.class);
- //根据代理对象的构造器创建代理对象
- Object o = declaredConstructor.newInstance(invocationHandler);
- //返回得到的代理对象
- return o;
- }
- }
复制代码
得到的署理对象的结构是怎么样的?
署理对象大抵结构:
- public class MProxy implements AInterface{
- private InvocationHandler ih;
-
- public MProxy(InvocationHandler ih) {
- this.ih = ih;
- }
- @Override
- public void rap() {
- ih.invoke();
- }
- @Override
- public void basketball() {
- ih.invoke();
- }
- }
复制代码 2.2.2动态署理的缺点
只剩下增强代码和目的方法硬编码
静态署理的缺点有:
1.只能署理某一类接口
2.若进行多次增强,大概署理类暴增
3.修改接口,要同时维护目的类和署理类
4.如果署理类的增强逻辑一致,大概造成大量重复代码
5.增强代码和目的方法硬编码
动态署理怎样优化的
对于静态署理的缺点1,动态署理只传入目的对象,目的对象可以是任意接口的,所以解决了
对于静态署理的缺点2、3、4,动态署理没有署理类,也解决了
但是对于静态署理的缺点5增强代码和目的方法硬编码,在动态署理的invoke方法
中还是没能制止,这个缺点在厥后的aop(面向切面编程才得以解决),它将方法的逻辑进行拆分,无侵入式的对方法进行增强。
2.2.3动态署理的拓展
本文章的动态署理是JDK根据接口实现的,此外还有第三方的动态署理,如cglib,它实现的原理同JDK差别,它是基于继承来实现的,子类继承父类重写父类方法实现的增强
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |