使用注解配置Spring AOP

在xml配置文件中初始化IoC容器,定义扫描注解的范围和启动Spring AOP注解模式。

<!--在IoC容器初始化时自动扫面四种组件类型注解并完成实例化
@Controller  当前mcv 控制类
@Repository  业务类 dao层  持久层
@Service  服务类
@Component  可以控制所有  不然确定的时候使用它就得了
-->
<context:component-scan  base-package="top.xiongmingcai"/><!--定义扫描注解作用范围-->

<!--启动AOP注解模式-->
<aop:aspectj-autoproxy/>

既然AOP采用注解,则IoC也采用注解开发,给对应的Dao标记@Repository,对应的Service标记@Service,给对应的注入标记@Resource(这里可以注入在属性上,也可以注入在set方法上)。

然后给切面类进行Aop注解的标记:

@Component //标记当前类为组件
@Aspect //说明点前类是切面类
public class MethodChecker {
    //ProceedingJoinPoint 是JoinPoint 升级版
    @Around("execution( public * top.xiongmingcai..*.*(..)))")
    public Object check(ProceedingJoinPoint pjp) throws Throwable {
        Object ret;
        try {
            long startingTime = new Date().getTime();
            //获得目标函数执行返回值
            //控制目标方法是否执行
            ret = pjp.proceed();
            long endTime = new Date().getTime();

            long duration = endTime - startingTime;
            if (duration >= 1000) {
                String targetClassName = pjp.getTarget().getClass().getName();
                String targetMethodName = pjp.getSignature().getName();

                SimpleDateFormat sdf = new SimpleDateFormat();
                String now = sdf.format(new Date());
                System.out.println("---->" + now + ":" + targetClassName + "." + targetMethodName + "用时:" + duration);
            }
        } catch (Throwable throwable) {
            System.out.println("Exception message = " + throwable.getMessage()); //捕获异常
            throw throwable;
        }
        return ret;
    }
}
@Component //标记当前类为组件
@Aspect //说明点前类是切面类
//切面类
public class MethodAspect {
    //切面方法,用于扩展额外功能
    //JoinPoint 连接点 通过连接点可以获取目标类/方法的信息
    @Before("execution(* top.xiongmingcai..*.*(..)))")
    public void printExecutionTime(JoinPoint joinPoint) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
        String now = simpleDateFormat.format(new Date());
        //获取目标类
        String targetClassName = joinPoint.getTarget().getClass().getName();
        //获取目标方法
        String targetMethodName = joinPoint.getSignature().getName();
        System.out.println("---->" + now + ":" + targetClassName + "." + targetMethodName);

        Object[] args = joinPoint.getArgs();
        for (Object arg : args) {
            System.out.println("--->参数 : " + arg);
        }
    }
    @After("execution(* top.xiongmingcai..*.*(..)))")
    public void doAfter(JoinPoint joinPoint) {
        System.out.println("<----MethodAspect.doAfter");
    }
    @AfterReturning(pointcut="execution(* top.xiongmingcai..*.*(..)))", returning = "ret")
    public void doAfterReturning(JoinPoint joinPoint ,Object ret){
        System.out.println("返回后通知 <---" + ret);
    }
    @AfterThrowing(pointcut="execution(* top.xiongmingcai..*.*(..)))", throwing= "th")
    public void doAfterThrowing(JoinPoint joinPoint,Throwable th){
        System.out.println("异常通知 <---" + th);
    }
}

  • @AfterReturning - 如果方法返回成功,则将函数标记为在切入点覆盖的方法之前执行的通知。
  • @Pointcut - 将函数标记为切入点
  • @After - 将函数标记为在切入点覆盖的方法之后执行的通知。
  • execution( expression ) - 涵盖应用通知的方法的表达式。
  • throwing - 返回的异常名称。
  • returning - 要返回的变量的名称

相关代码示例
https://github.com/MingCaiXiong/spring-learn/commit/b9e3c5505db4b7e74b656050b679eed6f7603368