乐趣区

Spring-Boot-面向切面编程

目录

  • 前言
  • 编程范式主要有以下几类
  • aop 注解
  • 用法

前言

spring 提供两个核心功能,一个是 Ioc(控制反转),另一个是 Aop(面向切面编程),Ioc 有助于应用对象之间的解耦,AOP 则可以实现横切关注点(如日志、安全、缓存、重复提交和事务管理)与他们所影响的对象之间的解耦。

编程范式主要有以下几类

  • AOP(Aspect Oriented Programming)面向切面编程
  • OOP(Object Oriented Programming)面向对象编程
  • POP(procedure oriented programming)面向过程编程
  • FP(Functional Programming)面向函数编程

aop 注解

AOP 主要包含了通知、切点和连接点灯术语,介绍如下:

  • 通知(Advice)

通知定义了切面是什么以及何时被调用,何时调用包含以下几种:

  1. Before 在方法被调用之前调用通知
  2. After 在方法完成之后调用通知,无论方法执行是否成功
  3. After-returning 在方法成功执行之后调用通知
  4. After-throwing 在方法抛出异常后调用通知
  5. Around 通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为
  • 切点(PointCut)

通知定义了切面是什么和何时被调用,切点定义了何处被调用,切点的定义会匹配通知所要织入的一个或多个连接点,我们通常使用明确的类的方法名称来指定这些切点,或是利用正则表达式定义匹配的类和方法名称来指定这些切点。

  • 连接点(JoinPoint)

连接点是在应用执行过程中能够插入切面的一个点,这个点可以是调用方法时,抛出异常时,甚至是修改一个字段时,切面代码可以利用这些连接点插入到应用的正常流程中,并添加新的行为,如日志、安全、事务、缓存等。

  • @Aspect: 切面,由通知和切入点共同组成,这个注解标注在类上表示为一个切面。
  • @Joinpoint: 连接点,被 AOP 拦截的类或者方法,在前置通知中有介绍使用 @Joinpoint 获取类名、方法、请求参数。
  • Advice: 通知的几种类型
  • @Before: 前置通知,在某切入点 @Pointcut 之前的通知
  • @After: 后置通知,在某切入点 @Pointcut 之后的通知无论成功或者异常。
  • @AfterReturning: 返回后通知,方法执行 return 之后,可以对返回的数据做加工处理。
  • @Around: 环绕通知,在方法的调用前、后执行。
  • @AfterThrowing: 抛出异常通知,程序出错跑出异常会执行该通知方法。
  • @Pointcut: 切入点,从哪里开始。例如从某个包开始或者某个包下的某个类等。

用法

AOP 在 spring 中有两种配置方式,一是 xml 配置的方式,二是自动注解的模式。

自动注解 AOP
声明切面类,包含注解 @Aspect 以及何时执行通知(Advice)
package com.ganji.demo.service.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Service;

/**
 * Created by admin on 2015/9/2.
 */
@Aspect
@Service
public class XmlAopDemoUserLog {

// 配置切点 及要传的参数   
    @Pointcut("execution(* com.ganji.demo.service.user.UserService.GetDemoUser(..)) && args(id)")
    public void pointCut(int id)
    { }

// 配置连接点 方法开始执行时通知
    @Before("pointCut(id)")
    public void beforeLog(int id) {System.out.println("开始执行前置通知  日志记录:"+id);
    }
//    方法执行完后通知
    @After("pointCut(id)")
    public void afterLog(int id) {System.out.println("开始执行后置通知 日志记录:"+id);
    }
//    执行成功后通知
    @AfterReturning("pointCut(id)")
    public void afterReturningLog(int id) {System.out.println("方法成功执行后通知 日志记录:"+id);
    }
//    抛出异常后通知
    @AfterThrowing("pointCut(id)")
    public void afterThrowingLog(int id) {System.out.println("方法抛出异常后执行通知 日志记录"+id);
    }

//    环绕通知
    @Around("pointCut(id)")
    public Object aroundLog(ProceedingJoinPoint joinpoint,int id) {
        Object result = null;
        try {System.out.println("环绕通知开始 日志记录"+id);
            long start = System.currentTimeMillis();

            // 有返回参数 则需返回值
            result =  joinpoint.proceed();

            long end = System.currentTimeMillis();
            System.out.println("总共执行时长" + (end - start) + "毫秒");
            System.out.println("环绕通知结束 日志记录");
        } catch (Throwable t) {System.out.println("出现错误");
        }
        return result;
    }
}

以上即实现 aop。

退出移动版