logUtil
package com.lyj.utils;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* 如何将这个类(切面类)中的这些方法(通知方法)动态的在目标方法运行的各个位置切入
* @author Administrator
*
*/
@Order(1)//改变优先级,数值越小优先级越高
@Aspect
@Component
public class LogUtils {
/**
* 告诉Spring每个方法都什么时候运行
* [1]@Before:前置通知,在方法执行之前执行
[2]@After:后置通知,在方法执行之后执行
[3]@AfterRunning:返回通知,在方法返回结果之后执行
[4]@AfterThrowing:异常通知,在方法抛出异常之后执行
[5]@Around:环绕通知,围绕着方法执行
抽取可重用的切入点表达式
1.随便声明一个没有实现的返回void的空方法
2.表注@Pointcut
*/
@Pointcut("execution(public int com.lyj.impl.MyCalc.*(int, int))")
public void hahaPoint(){
}
//之前,写切入表达式
//excution(方法权限 返回类型 方法签名)
@Before("hahaPoint()")
public static void logStart(JoinPoint joinPoint){
//获取到目标方法运行时使用的参数
Object[] args = joinPoint.getArgs();
Signature signature = joinPoint.getSignature();
String name = signature.getName();
System.out.println("[LogUtils切面打印]【"+name+"】方法开始执行,用参数列表"+Arrays.asList(args));
}
/**
* 切入点表达式的写法:
* 固定格式:execution([权限修饰符] [返回值类型] [简单类名/全类名] [方法名]([参数列表]))
* 通配符:
* *:一个或多个字符
* 任意一个参数 ("execution(public int com.lyj.impl.MyCalc.*(int, *))"
* 匹配一层路径
* ..:匹配任意多个参数,任意类型 execution(public int com.lyj.impl.MyCalc.*(..)
* 匹配任意多层路径 execution(public int com.lyj..MyCalc*.*(..)
* 权限位置不写就是任意权限
* 记住两种:
* 最精确的:execution(public int com.lyj.impl.MaCalc.add(int,int))
* 最模糊的:execution(* *.*(..))千万别写
*
*/
//正常完成之后
/**
* 告诉Springresult是干什么的
* @param joinPoint
* @param result
*/
@AfterReturning(value="hahaPoint()",returning="result")
public static void logReturn(JoinPoint joinPoint,Object result){
Signature signature = joinPoint.getSignature();
String name = signature.getName();
System.out.println("[LogUtils切面打印]【"+name+"】方法执行结束,计算结果是"+result);
}
/**
* 细节四:我们可以在通知方法运行的时候,拿到目标方法的详细信息
* 1)只需要为通知方法的参数列表上写一个参数
* JoinPoint joinPoint;封装了当前目标方法的详细信息
*/
//出现异常之后
@AfterThrowing(value="hahaPoint()",throwing="exception")
public static void logException(JoinPoint joinPoint,Exception exception){
System.out.println("[LogUtils切面打印]【"+joinPoint.getSignature().getName()+"】方法执行出现异常,异常信息是"+exception);
}
//结束
/**
* Spring对通知方法的要求不严格,唯一有要求的就是方法的参数列表一定不能乱写
* 通知方法是Spring利用反射调用的,每次方法调用的确定这个方法的参数表的值
* 参数表上的每一个参数,Spring都得知道是干嘛的,不知道的参数一定要告诉Spring
* @param joinPoint
*/
@After("hahaPoint()")
public static void logEnd(JoinPoint joinPoint){
System.out.println("[LogUtils切面打印]【"+joinPoint.getSignature().getName()+"】方法最终结束");
}
/**
* @throws Throwable
* @Around:环绕通知 是Sping中最强大的同值
* 四合一通知就是环绕通知:环绕通知中有一个参数ProceedingJoinPoint pjp
* 环绕通知优先于普通通知执行
* 环绕方法还可以修改目标方法,普通方法不行
* 环绕只影响当前切面
*/
//@Around("hahaPoint()")
public Object myAround(ProceedingJoinPoint pjp) throws Throwable{
Object[] args = pjp.getArgs();
String name = pjp.getSignature().getName();
//利用反射推进目标方法运行,就是method.invoke(obj,args)
Object proceed=null;
try {
System.out.println("环绕前置通知,"+name+"方法开始");
proceed = pjp.proceed(args);
System.out.println("环绕返回通知,"+name+"方法返回,返回值:"+proceed);
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("环绕异常通知,"+name+"方法异常,异常信息:"+e);
}finally{
System.out.println("环绕后置通知,"+name+"方法结束");
}
//反射调用后的返回值也一定返回出去
return proceed;
}
}
ValidateAspect
package com.lyj.utils;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Order(2)
@Aspect
@Component
public class ValidateAspect {
@Before("com.lyj.utils.LogUtils.hahaPoint()")
public void logStart(JoinPoint joinPoint) {
// 获取到目标方法运行时使用的参数
Object[] args = joinPoint.getArgs();
Signature signature = joinPoint.getSignature();
String name = signature.getName();
System.out.println("[validate切面]【" + name + "】方法开始执行,用参数列表" + Arrays.asList(args));
}
@AfterReturning(value = "com.lyj.utils.LogUtils.hahaPoint()", returning = "result")
public static void logReturn(JoinPoint joinPoint, Object result) {
Signature signature = joinPoint.getSignature();
String name = signature.getName();
System.out.println("[validate切面]【" + name + "】方法执行结束,计算结果是" + result);
}
@AfterThrowing(value = "com.lyj.utils.LogUtils.hahaPoint()", throwing = "exception")
public static void logException(JoinPoint joinPoint, Exception exception) {
System.out.println("[validate切面]【" + joinPoint.getSignature().getName()
+ "】方法执行出现异常,异常信息是" + exception);
}
@After("com.lyj.utils.LogUtils.hahaPoint()")
public static void logEnd(JoinPoint joinPoint) {
System.out
.println("[validate切面]【" + joinPoint.getSignature().getName() + "】方法最终结束");
}
}
Test
/**
* 正常执行:@Before--@After--@AfterReturning
* 异常执行:@Before--@After--@AfterThrowing
*/
@Test
public void test2(){
MyCalc bean = ioc.getBean(MyCalc.class);
//bean.div(1, 0);
System.out.println("===========");
bean.add(1, 1);
}