spring AOP AspectJ 定义切面实现拦截
总结记录一下AOP常用的应用场景及使用方式,如有错误,请留言.
1. 讲AOP之前,先来总结web项目的几种拦截方式
A: 过滤器
使用过滤器可以过滤URL请求,以及请求和响应的信息,但是过滤器是只是针对J2EE规范实现的,无法判断ServletRequest请求是由哪个controller方法处理
B: 拦截器
拦截器可以获取到URL的请求和响应信息,以及处理请求的controller方法信息,但是无法获取方法的参数,要使用spring 提供的拦截器,具体的做法如下:
a. 实现spring 提供的拦截器接口
b. 实现拦截器接口的3个方法,方法的参数 handler 实际上就是处理请求的 controller的方法声明, 可强转为 HandlerMethod 对象,HandlerMethod对象可以得到方法所在控制器类名,方法名称,但是无法获取方法的参数
--如果想获取参数信息,使用切面Aspect(spring核心功能 AOP的实现)
ps: 拦截器会拦截所有控制器的方法的调用,不光是我们自己写的,spring 框架提供的控制器也会被拦截
C: 切面
切面能获取到处理请求的方法,方法所属的类实例,方法的返回值、全类名、参数类型,方法的上注解等信息
ps: spring AOP 是基于 切面(AspectJ) 实现的
关于以上几种拦截方式执行顺序的说明:
过滤器优先于拦截器执行,拦截器优先于切面执行,但是晚于切面结束,最后过滤器晚于拦截器结束
具体顺序如下:
过滤器DoFilter方法开始->拦截器preHandle方法开始执行->切面方法开始->controller方法->切面方法结束->拦截器postHandle,afterCompletion方法开始执行,执行后拦截器结束->过滤器DoFilter方法结束
程序出现异常的处理顺序:
如果 controller方法 出现异常,最先捕获到异常的是的切面,如果切面抛出异常,由控制器异常处理器处理,如果控制器异常处理器不处理,异常会抛到拦截器,如果拦截器未处理,异常会抛到过滤器,如果过滤器未处理会抛到tomcat返回给用户
2. 关于AOP的介绍
有一篇博客已经介绍的很详细了 这里直接引用过来,大家也可以访问原地址获取更多: https://blog.csdn.net/wuruijiang/article/details/78970720
-- 什么是AOP
AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。
而AOP技术则恰恰相反,它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP代表的是一个横向的关系,如果说“对象”是一个空心的圆柱体,其中封装的是对象的属性和行为;那么面向方面编程的方法,就仿佛一把利刃,将这些空心圆柱体剖开,以获得其内部的消息。而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹。
使用“横切”技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。Aop 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。正如Avanade公司的高级方案构架师Adam Magee所说,AOP的核心思想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。”
实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。
-- AOP使用场景
AOP用来封装横切关注点,具体可以在下面的场景中使用:
Authentication 权限
Caching 缓存
Context passing 内容传递
Error handling 错误处理
Lazy loading 懒加载
Debugging 调试
logging, tracing, profiling and monitoring 记录跟踪 优化 校准
Performance optimization 性能优化
Persistence 持久化
Resource pooling 资源池
Synchronization 同步
Transactions 事务
-- AOP相关概念
方面(Aspect):一个关注点的模块化,这个关注点实现可能另外横切多个对象。事务管理是J2EE应用中一个很好的横切关注点例子。方面用spring的 Advisor或拦截器实现。
连接点(Joinpoint): 程序执行过程中明确的点,如方法的调用或特定的异常被抛出。
通知(Advice): 在特定的连接点,AOP框架执行的动作。各种类型的通知包括“around”、“before”和“throws”通知。通知类型将在下面讨论。许多AOP框架包括Spring都是以拦截器做通知模型,维护一个“围绕”连接点的拦截器链。Spring中定义了四个advice: BeforeAdvice, AfterAdvice, ThrowAdvice和DynamicIntroductionAdvice
切入点(Pointcut): 指定一个通知将被引发的一系列连接点的集合。AOP框架必须允许开发者指定切入点:例如,使用正则表达式。 Spring定义了Pointcut接口,用来组合MethodMatcher和ClassFilter,可以通过名字很清楚的理解, MethodMatcher是用来检查目标类的 方法是否可以被应用此通知,而ClassFilter是用来检查Pointcut是否应该应用到目标类上
引入(Introduction): 添加方法或字段到被通知的类。 Spring允许引入新的接口到任何被通知的对象。例如,你可以使用一个引入使任何对象实现 IsModified接口,来简化缓存。Spring中要使用Introduction, 可有通过DelegatingIntroductionInterceptor来实现通知,通过 DefaultIntroductionAdvisor来配置Advice和代理类要实现的接口
目标对象(Target Object): 包含连接点的对象。也被称作被通知或被代理对象。POJO
AOP代理(AOP Proxy): AOP框架创建的对象,包含通知。 在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。
织入(Weaving): 组装方面来创建一个被通知对象。这可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他纯JavaAOP框架一样,在运行时完成织入。
3. spring AOP的一些注解及API 说明
在开发中通常我们会使用 AspectJ 注解实现.
A: 常用的切面有以下几种,它决定了切入方法的位置:
前置:@Before
后置:@After
返回值:@AfterReturing
异常:@AfterThrowing
环绕:@Around
B: 连接点
JoinPoint、ProceedJoinPoint 连接点 其实就是切面表达式覆盖的方法,根据该连接点可以获取多个信息,例如 处理请求的方法,方法所属的类实例,方法的返回值、全类名、参数类型,方法的上注解等信息,常用的方法如下:
getSignature():获取连接点方法的返回值、全类名、参数类型
getTarget():获取连接点方法所属的类实例
getArgs():获取连接点方法的参数列表
getThis() :获取代理对象本身
ProceedingJoinPoint继承JoinPoint子接口,它新增了两个用于执行连接点方法的方法 :
proceed() : 通过反射执行目标对象的连接点处的方法
proceed(java.lang.Object[] args) : 通过反射执行目标对象连接点处的方法,不过使用新的入参替换原来的入参
JoinPoint 一般用在除了@Around 注解的方法上,ProceedJoinPoint 一般用在@Around 中(因为需要使用 ProceedJoinPoint 的 proceed()方法进行目标方法的执行)
B: 切点表达式
切点表达式就是方法(连接点)的匹配表达式,用于说明切点要匹配的方法路径:
例如 : * com.qxl.web.controller.userController.*(..)
表示此方法在 com.qxl.web.controller.userController下的任何方法,方法包含任何参数,任何返回值 的方法上都能执行
第一个 * : 表示方法任意权限,返回值为任意值都能执行此增强逻辑
第二个 * : userController 下的任何方法都能执行此增强逻辑
(..) : 表示方法里的参数为任意值 (无论参数多少,大小,类型)都可以执行此增强逻辑
3. spring AOP 的具体例子, 具体可见代码
package com.qxl.web.aspect; import java.lang.reflect.Method; import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component; import com.qxl.web.controller.userController; /**
* 使用切面实现url拦截:
* 切片的实现分为2个步 A: 切入点(使用 @Before @After @Around 等注解实现 : 用于表示 在那些方法上(注解参数)起作用 ,在什么时候(注解类型)起作用)
* B: 增强 (起作用的时候执行的业务逻辑)
* 具体如下:
* 1. 定义一个类,添加 @Aspect 注解,表明这是一个切片类,同时加上@Component注解将这个类在spring容器中声明
* 2. 在你的增强逻辑的方法上使用 @Before @After @Around 等注解,可以传递参数 ProceedingJoinPoint 对象,
* ProceedingJoinPoint对象类似于拦截器的 handler,可获取增强的方法的信息,类的名称和方法名称以及方法参数等等
* 3. 编写逻辑代码完善要增强方法的逻辑,如下的handleControllerMethod方法
*
* @author qxl
*
*/
@Aspect // spring 切面类需要添加此注解
@Component
public class AspectDemo { //@Before //在要增强方法之前执行
//@After //在要增强方法之后执行
/**
* 在要增强方法上环绕执行(前后都可以执行)
* 注解参数: execution(* com.qxl.web.controller.userController.*(..))
* 表示此方法在 com.qxl.web.controller.userController下的任何方法,方法包含任何参数,任何返回值 的方法上都能执行
* 第一个 * : 表示方法返回值为任意值都能执行此增强逻辑
* 第二个 * : userController 下的任何方法都能执行此增强逻辑
* (..) : 表示方法里的参数为任意值 (无论参数多少,大小,类型)都可以执行此增强逻辑
* @throws Throwable
*/
@Around("execution(* com.qxl.web.controller.userController.*(..))")
public Object handleControllerMethod(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("Aspect start"); //getTarget() 获得连接点所属类的实例
Object target = pjp.getTarget();
if (target instanceof userController) {
System.out.println("当前连接点方法是userController类中的方法");
} //得到连接点方法的参数
Object[] args = pjp.getArgs();
for (Object arg : args) {
System.out.println("arg is "+ arg);
} //getSignature():signature是信号,标识的意思,获取被增强的方法相关信息
Signature signature = pjp.getSignature();
//得到方法名称
System.out.println("Aspect 拦截到了" + signature.getName() +"方法...");
//得到方法所在的包名
System.out.println("方法所在的包名:"+ signature.getDeclaringTypeName());
//得到方法上的注解--如果 方法上存在一个 @Permission 注解
MethodSignature methodSignature = (MethodSignature)signature;
Method method = methodSignature.getMethod();
if(method.isAnnotationPresent(Permission.class)){
//得到这个注解
Permission permission = method.getAnnotation(Permission.class);
//.....other operation
}
//获取方法参数类型
Class<?>[] parameterTypes = method.getParameterTypes();
// 得到方法的返回值类型
Class<?> returnType = method.getReturnType(); //proceed()方法用来调用ProceedingJoinPoint对象获取到的那个的方法(即执行切片要增强的那个方法),proceed()方法返回的Object就是增强方法的返回值
// 如果proceed()方法传递了参数,会替换原来方法的参数
Object object = pjp.proceed(); System.out.println("Aspect end");
return object;
} }
spring AOP AspectJ 定义切面实现拦截的更多相关文章
- 关于 Spring AOP (AspectJ) 该知晓的一切
关联文章: 关于Spring IOC (DI-依赖注入)你需要知道的一切 关于 Spring AOP (AspectJ) 你该知晓的一切 本篇是年后第一篇博文,由于博主用了不少时间在构思这篇博文,加上 ...
- 关于 Spring AOP (AspectJ) 你该知晓的一切
版权声明:本文为CSDN博主「zejian_」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明.原文链接:https://blog.csdn.net/javazej ...
- Spring AOP AspectJ
本文讲述使用AspectJ框架实现Spring AOP. 再重复一下Spring AOP中的三个概念, Advice:向程序内部注入的代码. Pointcut:注入Advice的位置,切入点,一般为某 ...
- Spring学习(十八)----- Spring AOP+AspectJ注解实例
我们将向你展示如何将AspectJ注解集成到Spring AOP框架.在这个Spring AOP+ AspectJ 示例中,让您轻松实现拦截方法. 常见AspectJ的注解: @Before – 方法 ...
- Spring AOP + AspectJ annotation example
In this tutorial, we show you how to integrate AspectJ annotation with Spring AOP framework. In simp ...
- Spring AOP + AspectJ Annotation Example---reference
In this tutorial, we show you how to integrate AspectJ annotation with Spring AOP framework. In simp ...
- 关于 Spring AOP (AspectJ) 你该知晓的一切 (转)
出处:关于 Spring AOP (AspectJ) 你该知晓的一切
- Spring AOP:面向切面编程,AspectJ,是基于注解的方法
面向切面编程的术语: 切面(Aspect): 横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象 通知(Advice): 切面必须要完成的工作 目标(Target): 被通知的对象 代理(Pr ...
- Spring AOP:面向切面编程,AspectJ,是基于spring 的xml文件的方法
导包等不在赘述: 建立一个接口:ArithmeticCalculator,没有实例化的方法: package com.atguigu.spring.aop.impl.panpan; public in ...
随机推荐
- Python操作MongoDB看这一篇就够了
MongoDB是由C++语言编写的非关系型数据库,是一个基于分布式文件存储的开源数据库系统,其内容存储形式类似JSON对象,它的字段值可以包含其他文档.数组及文档数组,非常灵活.在这一节中,我们就来看 ...
- IdeaJ 常见插件安装, 常用配置,常用快捷键
-- 系统是 Ubuntu 16.04 1, 插件: 2, 常见的设置: [1] 代码提示的修改: File --> settings --> Keymap --> MainMenu ...
- PHP----------一群猴子排成一圈,按1,2,...,n依次编号。
1.一群猴子排成一圈,按1,2,...,n依次编号.然后从第1只开始数,数到第m只,把它踢出圈,从它后面再开始数,再数到第m只,在把它踢出去...,如此不停的进行下去, 直到最后只剩下一只猴子为止,那 ...
- CSS之CSS的三种基本的定位机制(普通流,定位,浮动)
一.普通流 普通流中元素框的位置由元素在XHTML中的位置决定.块级元素从上到下依次排列,框之间的垂直距离由框的垂直margin计算得到.行内元素在一行中水平布置. 普通流就是html文档中的元素如块 ...
- IDEA 201809 Jrebel安装破解
jrebel介绍: JRebel是一款JAVA虚拟机插件,它使得JAVA程序员能在不进行重部署的情况下,即时看到代码的改变对一个应用程序带来的影响.JRebel使你能即时分别看到代码.类和资源的变化, ...
- Python中的sys.path.append()
当我们导入一个模块时:import xxx,默认情况下python解析器会搜索当前目录.已安装的内置模块和第三方模块 当运行脚本文件和导入模块不再同一目录下 import sys sys.path. ...
- 判断是否为JSON对象
$.ajax({ type: 'POST', url: url, success(function(data){ //判断是否为JSON对象 if(typeof(data) == "obje ...
- 论文阅读(XiangBai——【CVPR2017】Detecting Oriented Text in Natural Images by Linking Segments)
XiangBai——[CVPR2017]Detecting Oriented Text in Natural Images by link Segments 目录 作者和相关链接 方法概括 方法细节 ...
- eclipse中使用workset整理项目
eclipse项目过多怎么方便管理呢? 可以使用workset来进行管理.这里的workset跟.net 也就是visual studio中的项目解决方法类似,可以将项目.类库进行分开管理. 可以点击 ...
- Asp.Net Core WebApi 和Asp.Net WebApi上传文件
public class UpLoadController : ControllerBase { private readonly IHostingEnvironment _hostingEnviro ...