AOP是什么?

时间:2024-5-22    作者:老大夫    分类: SSM


AOP并不是 age of Putin 普丁的年龄,而是 Aspect Oriented Programming 面向切面编程。

就是一种代理模式,将非核心业务剥离出来。例如,打印计算前后的数据,如果每个类都要手动添加那就太累了。这就需要一个代理。

分为静态代理和动态代理。静态代理我们不用,因为它就是手动去写代理类,还是很繁琐。

动态代理分为JDK动态代理(拜把子接口模式),Cglib动态代理(认干爹模式,生成子类来使用)

而AOP框架又对动态代理进行了简化。编写增强类 + 注解来解决插入的问题

面向对象(OOP)的垂直开发模式,出现了 非核心代码冗余的问题,不方便管理。

面向切面编程(AOP)是一种横向开发模式

增强类的编写

/**
 * 增强类的内部要存储增强代码
 *
 * 1. 定义方法存储增强代码,具体定义几个根据插入位置定
 * 2. 使用注解配置  指定插入目标方法的位置
 *      前置  @Before
 *      后置  @AfterReturning
 *      异常  @AfterThrowing
 *      最后  @After
 *      环绕  @Around
 *
 *      try{
 *          //前置  @Before
 *          目标方法执行
 *          //后置  @AfterReturning
 *      }catch (Exception e)
 *      {
 *          //异常  @AfterThrowing
 *      }finally{
 *          //最后  @After
 *      }
 *
 * 3. 配置切点表达式  【选中插入的方法  切点】
 * 4. 补全注解@Component 和@Aspect
 *
 * spring AOP ---  重点是配置  -->   jdk/Cglib
 *
 * 5. 开启aspect注解的支持
 */

@Component
@Aspect
public class LogAdvice {
    @Before("execution(* com.atguigu.service.impl.*.*(..))")
    public void start(){
        System.out.println("方法开始了");
    }

    @After("execution(* com.atguigu.service.impl.*.*(..))")
    public void after(){
        System.out.println("方法结束了");
    }

    @AfterThrowing("execution(* com.atguigu.service.impl.*.*(..))")
    public void error(){
        System.out.println("方法报错了");
    }
}

环绕增强类

@Component
@Aspect
public class TxAroundAdvice {

    /**
     *  环绕通知,需要你在通知中,定义目标方法的执行!
     * @param pjp 目标方法
     * @return 目标方法的返回值
     * @throws Throwable
     */

    @Around("com.atguigu.pointcut.MyPointCut.pointCut()")
    public Object transaction(ProceedingJoinPoint pjp){

        Object[] args = pjp.getArgs();
        Object result=null;

        try{
        //增强代码
            System.out.println("开启事务");
            result = pjp.proceed(args);
            System.out.println("事务结束");
        }catch (Exception e){
            System.out.println("事务回滚");
        } catch (Throwable e) {
            throw new RuntimeException(e);
        } finally {
            System.out.println("finally最后执行.....");
        }

        return null;
    }
}

Order注解设置增强类的优先级

@Component
@Aspect
@Order(1)  //设置优先级,数字越小优先级越大
public class TxAdvice {

    @Before("com.atguigu.pointcut.MyPointCut.pointCut()")
    public void begin(){
        System.out.println("开启事务....");
    }

    @AfterReturning("com.atguigu.pointcut.MyPointCut.pointCut()")
    public void commit(){
        System.out.println("事务提交.....");
    }

    @AfterThrowing("com.atguigu.pointcut.MyPointCut.pointCut()")
    public void rollBack(){
        System.out.println("事务回滚......");
    }
}

增强类切点的复用

  1. 当前类中提取
    • 定义一个空方法
    • 注解@Pointcut()
    • 增强注解中引用切点表达式的方法,直接调用方法名
  2. 创建一个存储切点的类
    • 单独维护切点表达式
    • 其他类的切点方法 类的全限定符.方法名()

第一种

@Pointcut("execution(* com..impl.*.*(..))")
    public void pointCut(){}

@AfterReturning(value = "pointCut()",returning = "result")//正常结束会走这里
    public void afterReturning(JoinPoint joinPoint,Object result){

}

第二种

/**
* 定义一个存放切点的类,里面的方法使用切点表达式
* 使用全限定修饰符定位到类然后再.方法()同样实现切点的复用引用
*/
package com.atguigu.pointcut;

import org.aspectj.lang.annotation.Pointcut;

public class MyPointCut {

    @Pointcut("execution(* com..impl.*.*(..))")
    public void pointCut(){

    }

    @Pointcut("execution(* com..impl.*.*(..))")
    public void mPc(){

    }
}
@Component
@Aspect
public class LogAdvice {
    @Before("com.atguigu.pointcut.MyPointCut.pointCut()")
    public void start(){
        System.out.println("方法开始了");
    }

    @After("com.atguigu.pointcut.MyPointCut.pointCut()")
    public void after(){
        System.out.println("方法结束了");
    }

    @AfterThrowing("com.atguigu.pointcut.MyPointCut.pointCut()")
    public void error(){
        System.out.println("方法报错了");
    }
}

增强类获取目标的具体信息(方法、类名、返回值、参数......)


/**
 * 定义四个增强方法获取对象的方法信息,返回值,异常对象
 *      (JoinPoint joinPoint)
 *      joinPoint中就包含目标方法的信息
 *
 * 1. 定义方法 - 增强代码
 * 2. 使用注解 - 指定对应的位置
 * 3. 切点表达式,选中方法
 * 4. 切面和ioc的配置
 * 5. 开启aspect注解的支持
 *
 *  增强中获取目标信息
 *  1. 全部增强方法中获取,获取目标方法的信息 包括方法名  参数  访问修饰符  所属类的信息
 *      (JoinPoint joinPoint)
 *  *   joinPoint中就包含目标方法的信息
 *  2. 返回的结果,只在AfterReturning中
 *      (Object result)
 *      @AfterReturning(value = "execution(* com..impl.*.*(..))",returning = "result")//正常结束会走这里
 *      //代表result接收返回结果
 *  3. 获取异常信息,只在afterThrowing
 *      (JoinPoint joinPoint,Throwable throwable)
 *      @AfterReturning(value = "execution(* com..impl.*.*(..))",returning = "result")//正常结束会走这里
 *
 */

@Aspect
@Component
public class MyAdvice {

    @Before("execution(* com..impl.*.*(..))")
    public void before(JoinPoint joinPoint){
        //1. 获取方法所属类的信息
        String simpleName = joinPoint.getTarget().getClass().getSimpleName();
        //2. 获取方法名称
        int modifiers = joinPoint.getSignature().getModifiers();
        String modifier = Modifier.toString(modifiers);
        String methodName = joinPoint.getSignature().getName();
        //3. 获取参数列表
        Object[] args = joinPoint.getArgs(); //获取目标方法参数
    }

    @AfterReturning(value = "execution(* com..impl.*.*(..))",returning = "result")//正常结束会走这里
    public void afterReturning(JoinPoint joinPoint,Object result){
    }

    @After("execution(* com..impl.*.*(..))")
    public void after(JoinPoint joinPoint){
    }
    @AfterThrowing(value = "execution(* com..impl.*.*(..))",throwing = "throwable")
    public void afterThrowing(JoinPoint joinPoint,Throwable throwable){
    }
}

增强类的使用

正常从IOC获取目标对象就行(IOC实际存储的是代理对象),注意使用接口来拿对象,具体实现类不可以,然后使用方法。

@SpringJUnitConfig(value = JavaConfiguration.class)
public class SpringAopTest {

    //aop - 代理技术  -  因为实现类有接口,选择jdk代理  - 根据接口生成代理类 - 代理对象和目标对象是拜把子关系  - 必须使用接口接值
    //aop - ioc - 真正存储的是代理对象,而不是目标对象了
    @Autowired
    private Calculator calculator;

    @Test
    public void test(){
        int result = calculator.add(1, 0);
        System.out.println("result = " + result);
    }
}


扫描二维码,在手机上阅读

推荐阅读: