- 创建切面类
@Aspect
@Component
public class LogAspect {
@Pointcut("execution(public * com.example.controller.*.*(..))")
public void webLog(){}
@Before("webLog()")
public void deBefore(JoinPoint joinPoint) throws Throwable {
// 接收到请求,记录请求内容
ServletRequestAttributes attributes =
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 记录下请求内容
System.out.println("URL : " + request.getRequestURL().toString());
System.out.println("HTTP_METHOD : " + request.getMethod());
System.out.println("IP : " + request.getRemoteAddr());
System.out.println("CLASS_METHOD : " +
joinPoint.getSignature().getDeclaringTypeName() +
"." + joinPoint.getSignature().getName());
System.out.println("ARGS : " + Arrays.toString(joinPoint.getArgs()));
}
@AfterReturning(returning = "ret", pointcut = "webLog()")
public void doAfterReturning(Object ret) throws Throwable {
// 处理完请求,返回内容
System.out.println("方法的返回值 : " + ret);
}
//后置异常通知
@AfterThrowing("webLog()")
public void throwss(JoinPoint jp){
System.out.println("方法异常时执行.....");
}
//后置最终通知,final增强,不管是抛出异常或者正常退出都会执行
@After("webLog()")
public void after(JoinPoint jp){
System.out.println("方法最后执行.....");
}
//环绕通知,环绕增强,相当于MethodInterceptor
@Around("webLog()")
public Object arround(ProceedingJoinPoint pjp) {
System.out.println("方法环绕start.....");
try {
Object o = pjp.proceed();
System.out.println("方法环绕proceed,结果是 :" + o);
return o;
} catch (Throwable e) {
e.printStackTrace();
return null;
}
}
}
- aop注解说明
-
@Aspect
:标识为切面类,为容器识别 -
@Before
:前置增强,方法执行前执行 -
@AfterReturning
:后置增强,方法返回时执行 -
@After
:后置增强,方法抛出异常或正常退出时执行 -
@Around
:环绕增强
- 方法说明
- 除了@Around外,每个方法里都可以加或者不加参数JoinPoint,如果有用JoinPoint的地方就加,不加也可以
- JoinPoint里包含了类名、被切面的方法名,参数等属性,可供读取使用。
- @Around参数必须为ProceedingJoinPoint,pjp.proceed相应于执行被切面的方法。
- @AfterReturning方法里,可以加returning = “XXX”,XXX即为在controller里方法的返回值,本例中的返回值是“first controller”。
- @AfterThrowing方法里,可以加throwing = "XXX",供读取异常信息,如本例中可以改为:
@AfterThrowing(throwing = "ex", pointcut = "webLog()")
public void throwss(JoinPoint jp, Exception ex){
System.out.println("方法异常时执行.....");
}
- 关于切入点
execution函数用于匹配方法执行的连接点,语法为:
execution(方法修饰符(可选) 返回类型 方法名 参数 异常模式(可选))
参数部分允许使用通配符:
-
*
匹配任意字符,但只能匹配一个元素 -
..
匹配任意字符,可以匹配任意多个元素,表示类时,必须和*联合使用 -
+
必须跟在类名后面,如Horseman+,表示类本身和继承或扩展指定类的所有类
其他切入点注解:
-
@annotation
:表示标注了指定注解的目标类方法@annotation(org.springframework.transaction.annotation.Transactional)
表示标注了@Transactional
的方法 -
@args
:通过目标类方法的参数类型指定切点
@args(org.springframework.stereotype.Service)
表示有且仅有一个标注了@Service
的类参数的方法 -
@whthin
:通过类名指定切点
@with(examples.chap03.Horseman)
,表示Horseman的所有方法 -
@target
:通过类名指定,同时包含所有子类
@target(examples.chap03.Horseman)
且Elephantman extends Horseman,则两个类的所有方法都匹配
运算符:
- &&
@execution(* chop(..)) && @target(Horseman)
表示Horseman及其子类的chop方法 - ||
@execution(* chop(..)) || @args(String)
表示名称为chop的方法或者有一个String型参数的方法 - !
@execution(* chop(..)) and @!args(String)
表示名称为chop的方法但是不能是只有一个String型参数的方法
大部分情况下,我们需要指定顺序,最简单的方式就是在Aspect切面类上加上@Order(1)
注解即可,order越小最先执行,也就是位于最外层。像一些全局处理的就可以把order设小一点,具体到某个细节的就设大一点。