Spring AOP不进入before和业务方法,却进入其他切面的问题
由于业务需求,需要编写一个AOP用来记录一些外部接口的调用日志.
首先是引入切面要用到的jar包,maven工程加入如下所示:
然后是配置文件,由于要在controller层加上切面,因此需要在springMVC的配置文件上加上
<aop:aspectj-autoproxy proxy-target-class="true" />
如此,配置文件的修改就完成了.
接下来就是编写切面类了,代码如下:
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 切面类
* <p>
* 记录日志
*/
// 声明这是一个组件
@Component
// 声明这是一个切面Bean
@Aspect
public class LogAspect {
/**
* 日志记录工具
*/
private static final Logger LOGGER = LogManager.getLogger(LogAspect.class);
/**
* 默认构造函数
*/
public LogAspect() {
System.out.println("初始化切面");
}
/**
* 配置切入点,该方法无方法体,主要为方便同类中其他方法使用此处配置的切入点,第一种配置切入点的方法
* <p>
* 扫描com.test.controller.TestController下面的所有方法
* @see [类、类#方法、类#成员]
*/
@Pointcut("execution(* com.test.controller.Test1Controller..*(..))")
public void aspectTest1() {
}
/**
* 配置前置通知,使用在方法aspect()上注册的切入点,第二种配置切入点的方法
* <p>
* 同时接受JoinPoint切入点对象,可以没有该参数
*
* @param joinPoint切入点
* @see [类、类#方法、类#成员]
*/
@Before("execution(* com.test.controller.Test2Controller..*(..))")
private void beforeTest2(JoinPoint joinPoint) {
String className = joinPoint.getTarget().getClass().getName(); //类名
String methodName = joinPoint.getSignature().getName(); //方法名
}
@Before("aspectTest1()")
private void beforeTest1(JoinPoint joinPoint) {
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
}
/**
* 配置后置通知,使用在方法aspect()上注册的切入点
* <p>
* </p>
*
* @param joinPoint
* 切入点
* @see [类、类#方法、类#成员]
*/
@After("aspectTest1()")
private void after(JoinPoint joinPoint) {
System.out.println("after");
}
/**
* 配置环绕通知,使用在方法aspect()上注册的切入点
* <p>
* 记录方法开始到结束的耗时
*
* @param joinPoint
* 切入点
* @return Object 处理结果
* @throws Throwable
* 异常
* @see [类、类#方法、类#成员]
*/
@Around("aspectTest1()")
private Object around(JoinPoint joinPoint) throws Throwable {
System.out.println("环绕通知前....");
ProceedingJoinPoint tempJoinPoint = (ProceedingJoinPoint) joinPoint;
/*Object object = tempJoinPoint.proceed();*/
System.out.println("环绕通知后....");
//return object;
return null;
/**
* <配置后置返回通知,使用在方法aspect()上注册的切入点
* <p>
*
* @param joinPoint
* 切入点
* @see [类、类#方法、类#成员]
*/
@AfterReturning(returning = "rvt", value = "aspectTest1()")
public void afterReturn(JoinPoint joinPoint, Object rvt) {
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
String args = "";
for (int i = 0; i < joinPoint.getArgs().length; i++) {
args = args + joinPoint.getArgs()[i] + ",";
}
args = args.substring(0, args.length() - 1);
String OutParam="";
if(rvt!=null){
OutParam=rvt.toString();
}
System.out.println("rvt");
}
/**
* 配置抛出异常后通知,使用在方法aspectTest1()上注册的切入点
* <p>
* </p>
*
* @param joinPoint
* 切入点
* @param ex
* 异常
* @see [类、类#方法、类#成员]
*/
@AfterThrowing(pointcut = "aspectTest1()", throwing = "ex")
public void afterThrow(JoinPoint joinPoint, Exception ex) {
System.out.println("afterThrow");
}
}
切面类至此就写完了,
然后就是要切入的类和方法,这里就不写了.
写完之后运行,测试,发现,before的切入点并没有进去,而其他的切入点(除了AfterThrowing)均有输出,要切入的业务方法也没进去,
刚开始以为配置问题,不停地修改配置,什么加包扫描啊,配置实体啊,各种方法都不行,最后发现是因为自己偷懒,将环绕通知的进程方法注释调了,导致程序在进入切面之后,无法正常执行,将这个注释去掉之后,切面就可以正常使用了.
所以,以后在配置切面时,要么不写环绕的部分,要么就要写完,千万不要偷懒.