- AOP的介绍
- AOP相关概念
- 相关概念:
- 细谈通知
- Spring AOP使用
- 准备工作
- 前置通知具体实现
- 环绕通知
- 配置规则表达式解析
- Spring AOP原理
AOP的介绍
AOP:AOP是一种思想;面向切面编程。它对某一类的事情做集中处理;更准确的说是面向集中功能的编程
Spring AOP:AOP思想的一种实现
AOP作用:AOP 可以扩充多个对象的某个能⼒;像是对面向对象一种补充和完善。
登录功能判断
统⼀⽇志记录
统⼀⽅法执⾏时间统计
统⼀的返回格式设置
统⼀的异常处理
事务的开启和提交等
AOP相关概念
相关概念:
切面(类):代表一个AOP类型(处理的事件是什么);一个项目可能有多个AOP;对应不同功能的实现。比如:用户登录功能判断、日志的统计记录
切点(方法):定义拦截规则
通知(方法具体实现):切面在特定切入点处要执行的代码。执行AOP逻辑业务
连接点:可能触发这个切点(方法)的点叫连接点。比如:我们要进行删除文章;里面就涉及一个判断用户登录状态;这个删除文章按钮就是连接点
细谈通知
切面的目标是它要完成的工作;这个工作就是通知(描述了在哪些连接点上应用哪些通知)
在Spring切面类可以在方法加以下注解;设置其方法为通知方法;当满足条件后就进行方法的调用:
前置通知使⽤ @Before:通知⽅法会在⽬标⽅法调⽤之前执⾏。
后置通知使⽤ @After:通知⽅法会在⽬标⽅法返回或者抛出异常后调⽤。
返回之后通知使⽤ @AfterReturning:通知⽅法会在⽬标⽅法返回后调⽤。
抛异常后通知使⽤ @AfterThrowing:通知⽅法会在⽬标⽅法抛出异常后调⽤。
环绕通知使⽤ @Around:通知包裹了被通知的⽅法,在被通知的⽅法通知之前和调⽤之后执⾏⾃定义的⾏为。
通知方法:
前置通知:在目标方法调用之前执行的通知
后置通知:在目标方法调用之后执行的通知
环绕通知:在目标方法调用前、后执行通知(特别适合方法执行时间的统计)
异常通知:在目标方法抛出异常执行的通知
返回通知:在目标方法返回时候执行的通知
Spring AOP使用
准备工作
1:正常创建Spring项目;添加Spring Web依赖;添加AOP依赖
这个应用商店也不是万能的;所以我们得去中央仓库寻找依赖
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
使用:在启动类同级或者子类下创建切面
AOP的实现有:Spring AOP;AspectJ;而spring aop出的比较晚;aspectj比较早诞生并被广泛使用;spring aop也变成兼容这个东西。语法是AspectJ的;具体实现是Spring AOP这个框架。Spring AOP也保留这个注解名字是AspectJ。
前置通知具体实现
1:创建切点(定义拦截规则)
拦截内容设置:
这里拦截是固定的写法;通过修改里面的内容实现不同的拦截(我是要拦飞机还是拦火车呢)
- 就是不管什么返回值都去拦截。后面就是要拦截的包名+类名;先只拦截这里的。后面的 . *是拦截的方法。当你写的是.a那就是拦截a开头的方法。参数如果没要求就是括号里面两个点(…)。。如果只要拦截int参数;那你就写int。
2:切点通知实现
3:连接点实现
上面的操作还没有连接点(所有可能触发切点的点);它是不会触发前置方法的执行
通过以下效果发现确实拦截到;并且执行了前置方法(我们在配置规则里写的就是拦截Usercontorller的所有方法;如果你是在其它类就不会生效;具体看你是怎么配置规则的)
后置通知、异常通知、返回通知写法都是一样的;只是注解不同
环绕通知
环绕通知特殊一点;把事件的本身交给你;ProceedingJionPoint代表我要访问的方法本体;所以环绕通知可以完全控制方法调用流程的通知;你可以在中间做其它事情。比如:决定是否执行被通知的方法,以及如何处理异常和返回值。
上述的代码;我们通过一个调试的手段也能看到这个对象里面的情况;它确实去在中间调用我们的目标方法
我们在执行上述环绕通知;执行流程会受到前置方法和后置方法影响;所以我们得把前置方法给注释掉再进行测试。如果前置方法和后置方法都存在。执行顺序如下
配置规则表达式解析
AspectJ支持三种通配符:
""通配符:可以匹配任意个字符;只能匹配一个元素(包、类、方法、方法参数)
"…"通配符:可以匹配多个元素,表示类时必须和 * 联合使用
"+"通配符:表示按照类型匹配指定类的所有类;必须跟在类名后面;比如:com.cba.Stu+表示继承该类的所有子类包括本身。
execution(<修饰符><返回类型><包.类.⽅法(参数)><异常>)
中间是拦截的种类;修饰符是可以省略的。类后面可以加+;表示拦截它和它子类;方法可以用表示拦截所有方法;拦截所有参数可以用…
修饰符:一般省略;标识度不高;我们写修饰符通常都是public。* 表示任意标识符都可以
返回类型:不能省略;写void拦截返回没有值的;*代表任意
包:
类:
- 任意 、*test 则是以test结尾、Test *则是以Test开头、UserTest 固定类
方法名:
不能省略 * 任意、addUser 固定方法、add * 以add开头、*add 以add结尾
参数:
() 指定无参、(int)指定int 、(int,int)指定两个int、(…)任意参数
throws:
可省略,一般不写
Spring AOP原理
Spring AOP基于动态代理模式实现,主要分为JDK动态代理实现和CGLIB字节码生成实现两种方式。
使用代理就能帮你招待客人;遇到非法就拦截在外。如果我直接在目标对象处理;那我的添加登录效验的代码还得加入到逻辑里面;我通过代理就可以把登录没效验的筛选掉
动态代理:动态代理(根据程序特征在运行生成代码)spring AOP会根据不同场景选择动态代理的实现功能;
静态代理:手动编码实现代理类并在程序运行前进行编译的代理方式,代理类和目标类都是在编译期确定;提起写好的。
织入:代理生成时机
1:编译期;切⾯在⽬标类编译时被织⼊。这种⽅式需要特殊的编译器。AspectJ以这种方式织入
2:类加载期;切⾯在⽬标类加载到JVM时被织⼊。这种⽅式需要特殊的类加载器
,它可以在⽬标类被引⼊应⽤之前增强该⽬标类的字节码。
3:运行期;切⾯在应⽤运⾏的某⼀时刻被织⼊。⼀般情况下,在织⼊切⾯时,AOP容器会为⽬
标对象动态创建⼀个代理对象。SpringAOP以这种⽅式织⼊切⾯的。
动态代理实现方式:
JDK动态代理:通过反射实现;速度快;被代理的类一定要实现接口
CGLIB动态代理:通过字节码增强技术(生成动态子类;子类去调用父类方法;你看不到的);动态生成代理对象。(通过代理类的子类来实现的动态代理;不能被final修饰)