理解代理模式、并利用jdk动态代理+反射实现AOP设计

代理模式

要想理解代理模式,就要先明确两个概念

1. 委托类(委托人)

2. 代理类(代理人)

老师有一种解释方法就很好理解。
例如,

屋主卖房,将房子委托给中介去帮自己卖掉房子
得到结果,

  1. 屋主就是委托类
  2. 中介就是代理类。

屋主有卖房的权限,中介也有了卖房的权限,但是中介帮屋主卖房就可能执行额外的操作,例如夸房子多好多好,装饰房子。

也就是说,代理类能在委托类方法实现的基础上,额外的扩展功能操作。
这就是代理模式的优点。

千万不要小看这块优点,AOP设计思想恰恰是利用了这一点实现了对公共代码的复用。

下文用代理模式之静态代理实现卖房子,而且写完之后我会解释为什么会有动态静态之分,什么又是静态,什么又是动态,又为什么非得建立接口。

  1. 建立房子(House)接口

在这里插入图片描述
2. 建立屋主Master(委托类)

在这里插入图片描述4. 建立中介Agency (代理类)

在这里插入图片描述5. 建立客户customer(买房人)

在这里插入图片描述现在房子House,委托类Master、代理类Agency、客户Customer都有了。
委托类master不与客户customer见面, 全权交给代理类Agency与客户去交流。

好,至此,静态代理建立完毕,我来测试一下。

在这里插入图片描述执行结果:

  1. 房子怎么样?
  2. 我要卖房,价格100万
  3. 这个房子旁边环境优美!

第一句是客户问的,第二句是中介转达屋主意愿,第三句是中介自己说的。

找这么一个代理类的目的是什么呢?
你想啊,地球上有那么多卖房的人,当然不止一个人去找中介哦!
你看,中介说的一句话:“ 这个房子旁边环境优美!”
要想卖个好钱就得夸房子,夸房子这个动作是不分哪个房子的,反正只要你卖房,房子到了我中介手里,我就要夸它好。

这样一来,假如我有一百个屋主去找这个中介了,中介就会用同样的招式对待房子-----夸。

那么这个夸就成了所有房子的公共点了,你说是不是?!!!

同理,我再建立99个master委托类,我的代理类Agency根本不需要再建立,一个就够了! 代理类只需要转达委托类的意愿,剩下的夸是不是就是共用的?

这就是代理的优点啊!

以上是静态代理,上面这个代理类Agency是不是只能卖房啊!

除了屋主能作为委托类之外,在现实生活中能作为委托类的太多太多了!例如饭店老板是不是也能作为委托类?代理人就是经理是不是!
这是你就会发现,不同的委托类需要不同的代理类!而当你手动为委托类写一个代理类时,这就叫静态。

这就出现问题了!在现实生活中可能没有什么问题,但是在计算机中就有问题了。
难道我有一个委托类,就要再手动创建一个对应的代理类?
那不是很麻烦吗?
这就出现了一个新的名词,动态。它的出现就是为了解决这个问题,这就是两者的区别。

以下是动态代理

我先提出两个问题:

  1. 既然代理类不再手动创建,有没有什么好办法,让它在需要的时候建立,让它被动建立呢?
  2. 如果我用了一个代理类解决了问题,那么委托类里的方法呢?每个委托类都有不同的方法,在代理类里我该怎么解决呢?

解答:
在Java程序运行的时候再生成对应的代理类,岂不是解决了前面两个问题? 这是什么啊,这不就是反射的特征吗。

有很多人不明白代理模式与反射机制之间的关系,特别是在动态代理这里。
我个人的理解就是,代理模式它是一种思想,一种解决问题的模式。用代理模式能很好的解决公共问题。
但是反射机制,是在技术层面上的。

也就是说,实现AOP,就要用代理模式这种解决问题的思路,这个思路之下真正实现底层代码的就是反射机制。可以说成jdk动态代理利用了jvm反射机制。

  1. 创建代理工厂类Proxy。

在这里插入图片描述2. 创建测试类

在这里插入图片描述代理工厂类怎么就帮委托类生成代理类了呢?
那么这个生成的代理类还能做额外的操作了吗?比如夸。
那除了屋主委托类,再加一个饭店老板委托类,这个工厂还能为我们生成对应的不同代理类吗?
在测试里中,会发现,我没有再实例化代理类Agency了。

解读Proxy类

在这里插入图片描述

bind() 就是为我们生成了一个代理对象。利用的就是反射机制!

来看看newProxyInstance()这个方法底层作了什么操作。

为了节省时间和文章长度,我拿出几行源码中的关键代码。

1.final Class<?>[] intfs = interfaces.clone();
2.Class<?> cl = getProxyClass0(loader, intfs);
3.final Constructor<?> cons = cl.getConstructor(constructorParams);
4.return cons.newInstance(new Object[]{h});

分别代表,克隆接口,而生成代理类cl,获取cl构造方法,再根据反射机制创建代理对象。
想要了解反射机制的可以去我的另一篇博文:https://editor.csdn.net/md/?articleId=105706135

代理对象确定生成, 那么代理类的额外操作谁来执行呢?

来看invoke
在这里插入图片描述需要说明的是,在测试方法中,代理对象执行house.sale()的sale方法之前,会返回到Proxy执行invoke方法。
也就是说,凡是用了这样生成的代理对象,一旦代理对象调用任意方法,invoke方法会对其进行拦截,然后利用反射机制method.invoke() 去执行委托类对象(也可叫做目标对象)的方法sale。

也就是说,表面上我是用代理对象去执行sale操作了,其实在执行之前invoke会对其进行拦截,然后最终执行的还是委托类的sale方法。
(怎么拦截的我是不清楚,这个需要深入源码了。)
是不是觉得这个代理对象是多余的?其实我也觉得挺多余的。当然,你可以将Proxy这个处理工厂就当成一个代理类,这样看起来就不多余了。
因为所有委托类都需要经历这么一Proxy工厂。

直到这里,jdk动态代理就完成了。

我再创建一个公司Company接口,定义一个方法招人,再建立Boss类实现接口,代理类人事部就交给Proxy创建。

看测试:
在这里插入图片描述测试结果是调用委托类Boss里的招人方法。
输出结果:招人。

来看,我想在招人方法执行之后再执行一句,人未满。
这个“人未满” 我交给代理对象来执行。

我只需要在invoke里这样写:

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        Object obj = method.invoke(target,args);
        System.out.println("人未满");
        return obj;
    }

输出结果:
人事部招人
人未满

在之前执行就放在前面;就是这么简单。

你可能觉得:就这?

没错,AOP就是利用了这一点!
AOP作了什么呢?将统一的问题集中处理。比如我所有的方法执行都需要记录在日志里,都可能要抛异常。这就是公共问题。

这时候我只需要在工厂Porxy中作手脚即可!这么一来凡是经过Proxy生成过的代理对象,它一旦调用委托类的方法,Proxy就会对方法进行处理。

好累,不想写了,直接上代码吧。

  1. 定义接口Inters

在这里插入图片描述2. 定义委托类IntersImpl

在这里插入图片描述3. 定义切面Aspect

在这里插入图片描述4. 定义Proxy处理类

在这里插入图片描述
5. 测试结果

在这里插入图片描述
AOP原理就是这个,在spring中用了xml配置文件。如果想修改成xml形式而不知道怎么修改的,请看我的另一篇关于ioc的博文,里面有讲xml的读取与使用。链接:https://editor.csdn.net/md/?articleId=105706135

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值