1. 什么叫做拦路虎?
当你开着车疾驰在大道上,突然从路边窜出来一伙收费的,这伙收费的就是拦路虎。
同样,当你从停车场开车出来,收费杆就是拦路虎。
所以说,拦路虎就是在你执行你行为的过程中对你进行拦截,执行这种拦截动作的操作者就是拦路虎。
2. 应用程序中的拦路虎
当你访问一个页面,请求从客户端传入到后台,在请求执行的过程中,我们需要对请求在某个阶段进行拦截,这种行为就是拦路虎。
所以,我们可以认为,凡是对目标请求进行半路拦截的操作者都是拦路虎。
3.实现拦路虎的方式。
绿林好汉要拦截镖局,是因为他们事前打探了镖队一定路过某个地方,所以提前在某个地方进行埋伏,当镖局路过此地时,才能拦截他们进行下来的动作。
收费杆也是提前预置在固定的停车场出口处,当车辆扫描经过收费杆时,它就会拦截车辆,根据停车时长来确定对车辆执行什么动作。
如果是你,要想拦截一个请求,你会怎么实现?
毫无疑问,你首先要知道这个请求从哪里来,要到哪里去,要路过什么地方,然后你才能精准地在你想要拦截它的地方拦截它。
所以说,实现拦路虎这种机制,底层只有一种原理,那就是提前埋钩子。就跟埋 Di Lei 一样,当你经过时,你要踩到我我就炸,你没踩到就不炸,你踩到了把它排除了我也不炸。
相当于我们提前在某个阶段已经埋好了钩子一样,就等着你来挂,至于挂什么东西,那是你的行为,我们不做干预,我们只是提前埋好钩子。
总结:
实现拦路虎操作,就是提前埋钩子。
4.埋钩子
从整体上来讲,埋钩子分为两类方式:
(1)静态埋钩子。
(2)动态埋钩子。
5.静态埋钩子
静态埋钩子,毫无疑问,在编码阶段就必须显式地把钩子埋好,这样,当请求到达钩子时,才可以触发钩子执行。
一般静态埋钩子,需要服务端在设计程序之初,就提前暴露一个钩子接口,钩子接口中提供特定的方法,在程序设计之初,就将这个钩子接口对象埋在某个执行时期。
这样,当请求进来到这个执行周期时,就触发钩子执行指定的方法。Servlet中的Filter,Listener,以及spring和springboot等各种框架中,大量使用这种方式来指定拦路虎。它们把这种拦路虎根据具体设计方式的不同分别称为过滤器,拦截器等。
6.动态埋钩子
动态埋钩子,有时候我们在编码时并没有刻意地在程序的某个生命周期去埋钩子,让程序执行指定的钩子,但是我们还想让程序在执行到某个阶段的时候去执行我们指定的逻辑,这个时候可以使用jdk或者cglib提供的动态加载能力。
所谓的动态加载就是在程序运行时可以动态的为某个类或者接口在内存中生成一个虚拟的子类。
借助动态生成的这个子类,我们可以使用它来代理真正要操作的对象。通过动态代理对象去操作真实对象,这样就可以在流程操作真实对象的前后来通过代理对象插入指定的逻辑。
这样我们就可以达到,当我们在执行某个真实对象的目标方法的时候,来拦截住它,插入自定义逻辑。
7.总结java程序中常见的拦路虎操作
(1).使用静态埋钩子的方式
Servlet中的Filter过滤器,Listener监听器等,spring中的拦截器,spring和springboot中各种内置钩子等。
(2).使用动态埋钩子的方式
底层是动态代理。最成熟的就是spring的AOP。可以使用jdk的动态代理方式,也可以使用开源框架cglib的动态代理方式。反正动态代理就是动态地为某个接口或者某个类在内存中生成一个虚拟的子类,这样这个虚拟的子类就可以代理真正的目标对象,从而达到拦截某表对象某个具体方法的目的。
文档信息
- 本文作者:Marshall