手撕JAVA(三十二)轻量级AOP框架——lightAOP
内容涉及:泛型、反射、注解、动态代理。
分包
annotations:用于存放注解
bean:用于存放实体类
handler:用于存放动态代理中的处理器
interfaces:用于存放动态代理中的接口
interfacesImpl:用于存放接口的实现,也就是动态代理中的被代理对象(目标对象)。
utils:用于存放工具类,也是这个框架的核心包。
annotations包
annotations存放有三个自定义注解:
@before:只能允许用来注解方法,用来标注这是一个前置通知。
@after:只能允许用来注解方法,用来标注这是一个后置通知。
@section:只允许用来注解类,用来标注这是一个切面。
utils包
框架的核心包,此包存放框架的5大组件:
scanner:扫描器,用于扫描切面并向注册中心中登记注册切面以及切面中的通知。
resovler:解析器,用于解析注册中心中注册的切面及切面中的通知。并且调用执行器来执行通知。
executor:执行器,用于执行切面中的通知。
sectionRegistry:注册中心,用于存放切面的消息(信息就是当前切面中前置。后置通知有哪些)
bean包
bean包中存放的最重要的一个类就是regisInfo
一个regisInfo就是一个切面的详细信息。
ClassName:切面的名字(类名)
methodsName:切面中的所有方法名
五大核心组件
前文以及说过五大核心组件的作用,现在以一个切面被扫描、注册、解析、执行的完整流程来详解五大核心组件间的调用关系以及各自的源代码:
扫描
扫描由sanner(扫描器)来完成
首先是scanf方法去扫描传入的Class对象,通过注解来判断是否为切面,
如果是切面就通过反射来拿到类中的所有方法,再调用scan方法继续扫描这些方法
(这里偷懒没有定义异常,而是直接用的输出,hhhh,后面升级版本的时候再改吧~狗头)
scan方法会遍历类中的方法,通过注解判断方法是否是前置(后置)通知,
如果是前置(后置)通知就将其暂时存放到List中去,
扫描器中有两个成员变量:
beforeList:存放在scan中被扫描出来的前置通知。
afterList:存放在scanf中被扫描出来的后置通知。
所有方法扫描完后调用register方法向注册中心注册切面和切面中的通知
注册
扫描器的register方法其实就是通过beforeList、afterList来实例化出两个regisInfo,然后放入注册中心中的List去。
注册中心:
注册中心中有两个List分别存放前置、后置通知。
解析
解析由resovler(解析器)来完成,
解析器的工作很简单,就是去分别遍历注册中心中存放前后置通知的两个List,
遍历的过程中调用executor来执行通知。
执行
执行由executor来负责,
executor的工作也很简单,通过解析器解析出来的类名、方法两个参数加上反射来执行所有方法
切面切入
框架中使用动态代理来代理对象,切面就是在动态代理的处理器handler的核心方法invoke中切入的。
前置通知就放在method.invoke()的前面
后置通知就放在method.invoke()的后面
测试
首先准备代理对象及其接口:
准备切面:
测试方法:
(测试方法其实还有一部分功能性的方法,后期版本升级的时候会单独再做封装,抽出一个工具类来,最后只暴露给开发者一个借口)