当前位置: 首页 > article >正文

24.12.25 AOP

  • 前置通知
  • 环绕通知
  • 后置通知
  • 最终通知
  • 异常通知

API类似,只是生效的时机不一样,并且,不能保证,各个通知的顺序

try {
    //前置通知
    before();
    //环绕通知,内部是执行的方法
    around(proxy,method,args,methodProxy);
    //后置通知
    afterReturn();
} catch (Throwable e) {
    exception();//异常通知
}finally {
    after();//最终通知
}

前置通知

被访问的方法,执行之前执行的通知

先执行通知的方法,然后再执行被访问的方法本身

public void f2(JoinPoint joinPoint){
System.out.println("----------前置通知");
//被访问方法的参数
Object[] args = joinPoint.getArgs();
//被访问方法所在类的,bean对象
Object target = joinPoint.getTarget();
//被访问的方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
System.out.println(method.getName()+"被调用了,传入了参数:"+ Arrays.toString(args)+"---所在类:"+target);
}

环绕通知

public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("==========环绕通知开始=========");
    //调用方法,必须写的,如果不写,目标方法不会被调用
    //Object o 是被执行方法的返回值
    Object o = joinPoint.proceed();
    //
    MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    Method method = signature.getMethod();
    Object[] args = joinPoint.getArgs();
    //method.invoke(12);
    System.out.println("==========环绕通知结束========="+method.getName());
    return o;
}
  • 配置通知
<aop:aspect ref="test1">
  <!--前置通知,在切入点的方法,被访问之前,执行的方法-->
  <aop:before method="f2" pointcut-ref="q3"/>
  <aop:around method="aroundMethod" pointcut-ref="q3"/>
  <aop:after-throwing method="f3" pointcut-ref="q3"/>
  <aop:after method="f4" pointcut-ref="q3"/>
  <aop:after-returning method="f5" pointcut-ref="q3"/>
</aop:aspect>

SpringAOP原理

动态代理

注解AOP

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd"
>
    <context:component-scan base-package="com.javasm"/>

    <!--开启AOP注解-->
    <aop:aspectj-autoproxy/>
</beans>
//<aop:aspect ref='aspect2'>
@Component("aspect2")
@Aspect
public class TestAspect2 {

    //切点,标记
    @Pointcut("execution(* com.javasm.*.service.*.*.query*(..))")
    void f1(){}

    @Before("f1()")
    void before(JoinPoint joinPoint){
        System.out.println("注解前置通知");
    }
    @Around("f1()")
    Object aroundTest(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("-----环绕通知开始");
        Object proceed = joinPoint.proceed();
        System.out.println("------环绕通知结束");
        return proceed;
    }

    @After("f1()")
    void after(JoinPoint joinPoint){
        System.out.println("========最终通知");
    }
    //@AfterReturning("f1()")
    @AfterReturning(value = "f1()",returning = "msg")
    void afterReturn(JoinPoint joinPoint,Object msg){
        System.out.println("##########后置通知########返回值:"+msg);
    }

    //@AfterThrowing("f1()")
    @AfterThrowing(value = "f1()",throwing = "e")
    void afterThrowing(JoinPoint joinPoint,Throwable e){
        System.out.println("=========异常通知:"+e);
    }
}

自定义注解

自定义注解搭配AOP注解,灵活的控制方法

案例:

想在项目中记录日志

但是不是每个模块每个方法都记录

哪个方法需要记录,现在还不确定,但是要提前把业务逻辑写好

利用自定义注解,哪个方法需要增加日志,就在哪个方法上面加上自定义注解

  • 自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SaveLog {
    //String value();
}
  • 切面类
@Component
@Aspect
public class SaveLogAspect {

    @Resource
    LogService logService;

    //方法执行结束之后,保存日志
    @AfterReturning("@annotation(com.javasm.aspect.SaveLog)")
    public void saveLog(JoinPoint joinPoint){
        String msg = "%s方法,在%s时间,被调用了,参数是%s";
        //方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String methodName = method.getName();
        //时间
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = simpleDateFormat.format(new Date());
        //参数
        String parameters = Arrays.toString(joinPoint.getArgs());
        msg = String.format(msg,methodName,time,parameters);
        logService.save(msg);
    }
}

@SaveLog

  • 控制到类

案例:

统计方法运行消耗的时间

统计某一个类所有的方法

@within必须是在类级别生效

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Time {
}
@Component
@Aspect
public class TimeAspect {

    @Around("@within(com.javasm.aspect.Time)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object proceed = joinPoint.proceed();
        long time = System.currentTimeMillis() - start;
        String msg = "%s方法,运行消耗的时间是%s毫秒";
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String methodName = signature.getMethod().getName();

        System.out.printf(msg,methodName,time);
        return proceed;
    }
}

@Time

配置类启动

@Configuration
@ComponentScan("com.javasm")
@EnableAspectJAutoProxy//开启注解AOP
public class JavasmConfig {


}
AnnotationConfigApplicationContext applicationContext =
                new AnnotationConfigApplicationContext(JavasmConfig.class);


http://www.kler.cn/a/450725.html

相关文章:

  • vue中做一个最多输入一位小数且可以为负数的输入框(包含最前面最后面为小数点及多个-符号与前导零校验)
  • Dubbo简单总结
  • Vue + ECharts 实现山东地图展示与交互
  • Spring常见面试题总结
  • Spring-Boot 插件
  • 【Linux探索学习】第二十三弹——理解文件系统:认识硬件、探索文件在硬件上的存储问题
  • CASA模型相关遥感数据及MODIS NDVI、FPAR遥感产品数据时序重建
  • SpringBoot3——Web开发
  • 软件测试之压力测试【详解】
  • 安卓修改进程数 termux报错signal 9 vmos
  • webpack3 webpack4 webpack5 有什么区别
  • Java重要面试名词整理(四):并发编程(下)
  • 代理模式(JDK,CGLIB动态代理,AOP切面编程)
  • 产品经理如何做运营数据分析?
  • JVM简介—垃圾回收器和内存分配策略
  • MySQL用户授权
  • Mysql大数据量表分页查询性能优化
  • 【从零开始入门unity游戏开发之——unity篇01】unity6基础入门开篇——游戏引擎是什么、主流的游戏引擎、为什么选择Unity
  • Pytorch | 利用BIM/I-FGSM针对CIFAR10上的ResNet分类器进行对抗攻击
  • SharpDX 从入门到精通:全面学习指南
  • 【人工智能】Python中的机器学习管道:如何用scikit-learn构建高效的ML管道
  • 【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
  • 学生资助管理系统:提升资助决策的数据支持
  • 实力认可 | 通付盾入选《ISC.AI 2024创新能力全景图谱》五项领域
  • 拓展AI超级智能后的人类生活场景
  • 深入探究 Java 中的 setText