Spring Aop

AOP(Aspect-Oriented  Programming)面向切面编程 

          是一种新的方法论,是对传统OOP(Object-Oriented  Programming,面向对象编程)的补充,是一种通过动态代理实现程序功能扩展和统一维护的一种技术

        OOP:面向对象编程,纵向继承机制,重点关注类

        AOP:面向切面编程,横向提取机制,重点关注方法

一、动态代理

 原理:一个代理将原本的对象包装起来,然后用该代理对象“取代”原始对象。任何对原始对象的调用都要通过代理,代理对象决定是否以及何时将方法调用转到原始对象上。

二、AOP 

1、准备工作

        <!--spring-aspects的jar包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.3.1</version>
        </dependency>
<!--    开启组件扫描【使用注解】-->
    <context:component-scan base-package="com.atguigu.annotationAspectJ" ></context:component-scan>

<!--    开启AspectJ注解支持【自动为目标对象创建代理对象】-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

2、AOP术语:

(1)横切关注点:非核心业务称为横切关注点

(2)切面<Aspect>:将横切关注点提取到类中,类称为切面

(3)通知<Advice>:将横切关注点提取到类中后,横切关注点更名为:通知

(4)目标<Taeget>:目标对象【Calclmpl】

(5)代理<Proxy>:代理对象

@Autowired
    private Calc calc;  //com.sun.proxy.$Proxy21

(6)连接点<Joinpoint>:先将横切关注点提取切面类中【通知】,再动态将通知织入回业务代码中;织入位置称之为,连接点。【织入之前】

(7)切入点<pointcut>:先将横切关注点提取切面类中【通知】,再动态将通知织入回业务代码中;织入位置称之为,连接点。【织入之后】

3、AOP切入点表达式

  (1) 基本语法

          execution( [权限修饰符] [返回值类型] [简单类名/全类名] [方法名] ( [参数列表类型] )

execution(public int com.atguigu.annotationAspectJ.CalcImpl.add(int,int))

  (2) 表达式常用通配符

        【*】:可以代表任意权限修饰符和返回值类型 ; 任意包 | 任意类全限定名 ; 任意方法名

        【..】:代表任意参数类型 | 参数数量

(3) 重用切入点表达式

         提取公共切入点表达式

 @Pointcut("execution(* com.atguigu.annotationAspectJ.CalcImpl.*(..))")
    public void myPointCut(){
    }

        提取后的方法名,作为切入点表达式

@Before("myPointCut()")
    public void methodBefore(JoinPoint joinPoint){

(4)AspectJ中支持通知

  •  前置通知:@Before  

        在业务代码执行前执行,如有异常也执行

  @Pointcut("execution(* com.atguigu.annotationAspectJ.CalcImpl.*(..))")
    public void myPointCut(){
    }

    /**
     * 配置通知【前置通知---在执行业务代码之前执行】
     * @param joinPoint
     */
    //@Before("execution(public int com.atguigu.annotationAspectJ.CalcImpl.add(int,int))")
    @Before("myPointCut()")
    public void methodBefore(JoinPoint joinPoint){
        //通过方法签名【方法名形参列表】,获取方法名
        String name = joinPoint.getSignature().getName();
        //获取参数
        Object[] args = joinPoint.getArgs();
        System.out.println("日志功能【前置通知】:执行"+name+"()方法之前,参数:"+ Arrays.toString(args));
    }
  •  后置通知:@After

        在业务代码执行之后执行,如有异常也执行

  /**
     * 后置通知【在执行业务代码之后执行】
     * @param joinPoint
     */
    @After("execution(* com.atguigu.annotationAspectJ.CalcImpl.*(..))")
    public void methodAfter(JoinPoint joinPoint){
        String name = joinPoint.getSignature().getName();
        //获取参数
        Object[] args = joinPoint.getArgs();
        System.out.println("日志功能【后置通知】:执行"+name+"()方法之前,参数:"+ Arrays.toString(args));
    }
  •  返回通知:@AfterReturning

        在业务代码返回结果后<后置通知之前>执行,如有异常不执行

        返回通知要求,returning="属性值"与入参中参数名一致

  @AfterReturning(value = "myPointCut()",returning = "rs")
    public void methodReturn(JoinPoint joinPoint,Object rs){
        String name = joinPoint.getSignature().getName();
        System.out.println("日志功能【返回通知】:执行"+name+"()方法,返回结果rs:"+ rs);
    }
  •  异常通知:@AfterThrowing

        在业务代码出现异常时<后置通知之前>执行,如有异常执行;无异常不执行

        异常通知要求,throwing="属性值"与参数名一致

 @AfterThrowing(value = "myPointCut()",throwing = "ex")
    public void methodThrowing(JoinPoint joinPoint,Exception ex){
        String name = joinPoint.getSignature().getName();
        System.out.println("日志功能【异常通知】:执行"+name+"()方法,出现异常ex:"+ ex);
    }
  •  环绕通知:@Around

        将业务代码<前置 | 后置 | 返回 | 异常>通知,整合一处

        环绕通知的参数,只能ProcessingJoinPoint

        

   @Around(value = "myPointCut()")
    public Object methodAround(ProceedingJoinPoint proceedingJoinPoint){
        Object rs = null;
        //获取方法名
        String name = proceedingJoinPoint.getSignature().getName();
        //获取参数
        Object[] args = proceedingJoinPoint.getArgs();

        try {
            //前置通知
            System.out.println("日志功能【前置通知】:执行"+name+"()方法之前,参数:"+ Arrays.toString(args));
            //执行目标对象的目标方法【add()】
            Object object = proceedingJoinPoint.proceed();
            //返回通知
            System.out.println("日志功能【返回通知】:执行"+name+"()方法,返回结果rs:"+ rs);
        } catch (Throwable ex) {
            ex.printStackTrace();
            System.out.println("日志功能【异常通知】:执行"+name+"()方法,出现异常ex:"+ ex);
        } finally {
            //后置通知
            System.out.println("日志功能【后置通知】:执行"+name+"()方法之前,参数:"+ Arrays.toString(args));
        }

        return rs;
    }

(5)切面优先级

        @Order(value=index)       index=正整数

        作用:设置切面优先级 ,数值越小,优先级越高

/**
 * Creates with IntelliJ IDEA.
 * Author: 李龙
 * Date: 2021/10/13 11:20
 * Description: TODO
 * Since  version-1.0
 * 日志切面
 */

@Component  //将当前类装配IOC容器中
@Aspect     //将当前类标识为一个切面【】
@Order(value = 2)
public class MyLogging {
}


/**
 * Creates with IntelliJ IDEA.
 * Author: 李龙
 * Date: 2021/10/13 16:41
 * Description: TODO
 * Since  version-1.0
 * 验证切面
 */
@Component
@Aspect
@Order(value = 1)
public class MyValidate {
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值