5、基于注解的AOP配置

2023-10-29

一、开启注解支持

1、概述

1、Spring AOP如同IoC一样支持基于XML和基于注解两种配置方式,基于注解所需的依赖和基于XML所需的依赖一致,其中spring-context包含了Spring IoC、Spring AOP等核心依赖,而aspectjweaver则是AspectJ框架的依赖,Spring使用该依赖来解析AspectJ的切入点表达式语法,以及AOP的注解支持。
2、开启AOP注解支持的方式:
  • 使用XML配置启用AOP注解。
  • 使用Java配置启用AOP注解。

2、使用XML方式的配置

1、加入aop命名空间,使用<aop:aspectj-autoproxy />标签即可,Spring将会查找被@Aspect注解标注的Bean,这表明它是一个切面Bean,然后就会进行AOP的自动配置。
2、属性说明:
  • proxy-target-class是否为被代理类生成CGLIB子类,只为接口生成代理子类(即:是否使用CGlib动态代理);默认为false,使用的是JDK代理
  • expose-proxy是否将代理的Bean暴露给用户,如果暴露,就可以通过AopContext类获得,默认不暴露
<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop.xsd
         http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context.xsd">

	<!--开启注解自动配置-->
    <aop:aspectj-autoproxy/>
</beans>

3、使用Java方式的配置

1、AOP的注解支持同样可以使用Java配置方式开启,从而彻底舍弃XML配置文件。
2、配置类上添加@EnableAspectJAutoProxy,该注解用于开启Spring AOP的注解自动配置支持。
3、属性说明:
  • proxyTargetClass是否为被代理类生成CGLIB子类,只为接口生成代理子类(即:是否使用CGlib动态代理);默认为false,使用的是JDK代理
  • exposeProxy是否将代理的Bean暴露给用户,如果暴露,就可以通过AopContext类获得,默认不暴露
/**
 * @Date: 2023/2/11
 * 开启AOP注解支持配置类
 * @Configuration注解:表示该类为一个配置类
 * @ComponentScan注解:用于扫描包上的注解将组件加载到IoC容器中
 */
@Configuration
@ComponentScan("com.itan.aop.*")
@EnableAspectJAutoProxy
public class AopConfig {
}

二、切面相关注解

1、@Aspect注解

1、@Aspect注解对应着XML配置中的<aop:aspect />标签,被该注解标注的类,会被当做切面类并且用于自动配置Spring AOP。如果类仅仅只标注了该注解,那么是不会被Spring组件扫描工具自动扫描到的,并且不会加入到IoC容器中,因此还需要搭配组件注册相关的注解一起使用(如:@Component)
2、切面类和普通类一样,可以有自己的方法和字段,还可以包含切入点(pointcut)、通知(advice)、声明(introduction),这些都是通过方法来绑定的。
3、切面类本身是不能成为其他切面通知的目标类,类上面标注了@Aspect注解之后,该类的Bean将从AOP自动配置Bean中排除,因此切面类里面的方法是不能被代理的。

2、@Pointcut注解

1、@Pointcut注解对应着XML配置中的<aop:pointcut />标签,用来定义一个切入点,在匹配的情况下执行通知,切入点表达式的语法都是一样的,请参考切入点声明规则
2、@Pointcut注解标注在一个切面类的方法上,方法名就是该切入点的名字,在通知中通过名字引用该切入点(XXX(),要带上括号),也可以将多个切入点组合成一个新的切入点(可以使用&&、||、!等运算符连接起来),XML配置中不具备该组合方式

3、通知相关注解

1、advice通知同样可以使用注解声明,并且绑定到一个方法上,一共有五种通知注解,分别和XML中的五中通知标签一一对应。
2、五种通知注解:
  • @Before:用于定义前置通知,在使用时,通常需要指定一个value属性值,该属性值用于指定一个切入点表达式(可以是已有的切入点,也可以直接定义切入点表达式)。
  • @AfterReturning:用于定义后置通知,在使用时可以指定pointcut或value和returning属性;其中pointcut/value这两个属性的作用一样,都用于指定切入点表达式;returning属性值是后置通知方法中的参数名,用来将切入点方法的返回值绑定到该参数上
  • @AfterThrowing:用于定义异常通知,在前置通知、切入点方法和后置通知中抛出异常之后可能会执行;在使用时可指定pointcut或value和throwing属性,其中pointcut/value用于指定切入点表达式;throwing属性值是异常通知方法中的参数名,用来将前置通知、切入点方法、后置通知执行过程中抛出的异常绑定到该参数上
  • @After:用于定义最终通知,不管是否异常,该通知都会执行;使用时需要指定一个value属性,用于指定一个切入点表达式。
  • @Around:用于定义环绕通知,使用时需要指定一个value属性,用于指定一个切入点表达式。
/**
 * @Date: 2023/2/11
 * 切面类
 * @Aspect:用于定义该类为一个切面类
 * @Component:将组件注册到IoC容器中,否则单单使用@Aspect是不会被组件扫描注解检测到的
 */
@Aspect
@Component
public class AnnoAspect {

    /**
     * 切入点,该切入点匹配service包下所有类所有方法
     */
    @Pointcut("execution(* com.itan.aop.service..*.*(..))")
    public void pointCut() {}


    /**
     * 前置通知
     */
    @Before(value = "pointCut()")
    public void before() {
        System.out.println("前置通知");
    }

    /**
     * 异常通知
     */
    @AfterThrowing(value = "pointCut()", throwing = "e")
    public void afterThrowing(Exception e) {
        System.out.println("异常通知,异常为:" + e.getMessage());
    }

    /**
     * 后置通知
     */
    @AfterReturning(value = "pointCut()", returning = "result")
    public void afterReturning(Object result) {
        System.out.println("后置通知,返回值为:" + result);
    }

    /**
     * 最终通知
     */
    @After(value = "pointCut()")
    public void afterFinally() {
        System.out.println("最终通知");
    }

    /**
     * 环绕通知
     * 一定要有ProceedingJoinPoint类型的参数
     */
    @Around(value = "pointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        System.out.println("环绕通知 --- 进入方法");
        Object[] args = point.getArgs();
        System.out.println("外部传入的参数:" + Arrays.toString(args));
        System.out.println(point.toString());
        System.out.println(point.toShortString());
        System.out.println(point.toLongString());
        System.out.println(point.getThis());
        System.out.println(point.getTarget());
        System.out.println(point.getSignature());
        System.out.println(point.getSourceLocation());
        System.out.println(point.getKind());
        System.out.println(point.getStaticPart());
        // proceed方法表示调用切入点方法,否则方法不会执行,args表示参数,proceed就是切入点方法的返回值
        Object proceed = point.proceed(args);
        System.out.println("环绕通知 --- 退出方法");
        return proceed;
    }
}
/**
 * @Date: 2023/2/11
 * 目标接口实现类
 */
@Service
public class CalculateServiceImpl implements CalculateService {
    public Integer add(int i, int j) {
        return i + j;
    }

    public int sub(int i, int j) {
        return i + j;
    }

    public int multiply(int i, int j) {
        return i * j;
    }

    public double divide(int i, int j) {
        return i / j;
    }
}
@Test
public void test04() {
    // 通过配置文件创建容器对象
    ApplicationContext context = new AnnotationConfigApplicationContext(AopConfig.class);
    CalculateService calc = context.getBean(CalculateService.class);
    System.out.println(calc.getClass());
    calc.add(2,3);
}
/**
 * 运行结果:可以看到默认情况下使用JDK代理:class com.sun.proxy.$Proxy28
 * class com.sun.proxy.$Proxy28
 * 环绕通知 --- 进入方法
 * 外部传入的参数:[2, 3]
 * execution(Integer com.itan.aop.service.CalculateService.add(int,int))
 * execution(CalculateService.add(..))
 * execution(public abstract java.lang.Integer com.itan.aop.service.CalculateService.add(int,int))
 * com.itan.aop.service.impl.CalculateServiceImpl@3e6f3f28
 * com.itan.aop.service.impl.CalculateServiceImpl@3e6f3f28
 * Integer com.itan.aop.service.CalculateService.add(int,int)
 * org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint$SourceLocationImpl@7357a011
 * method-execution
 * execution(Integer com.itan.aop.service.CalculateService.add(int,int))
 * 前置通知
 * 后置通知,返回值为:5
 * 最终通知
 * 环绕通知 --- 退出方法
 */

4、通知顺序

1、当同一个连接点方法中绑定了多个同一个类型的通知时,有时需要指定通知的执行顺序,在XML中通过<aop:aspect />切面标签中的order属性指定执行通知顺序,注解配置中也能实现通知执行顺序。
2、实现方式:
  • 通知类实现Ordered接口
  • 通知类标注@Order注解
  • 提示:未设置order值时,默认值为Integer.MAX_VALUE;值越小的切面,其内部的前置通知越先执行,后置通知越后执行。
/**
 * @Date: 2023/2/11
 * 通过@Order注解方式设置顺序
 */
@Aspect
@Component
@Order(Integer.MAX_VALUE - 2)
public class AnnoOrderAspect1 {
    /**
     * 切入点,该切入点匹配service包下所有类所有方法
     */
    @Pointcut("execution(* com.itan.aop.service..*.multiply(..))")
    public void pointCut() {}

    /**
     * 前置通知
     */
    @Before(value = "pointCut()")
    public void before() {
        System.out.println("AnnoOrderAspect1前置通知");
    }

    /**
     * 后置通知
     */
    @AfterReturning(value = "pointCut()", returning = "result")
    public void afterReturning(Object result) {
        System.out.println("AnnoOrderAspect1后置通知,返回值为:" + result);
    }

    /**
     * 最终通知
     */
    @After(value = "pointCut()")
    public void afterFinally() {
        System.out.println("AnnoOrderAspect1最终通知");
    }
}
/**
 * @Date: 2023/2/11
 * 通过实现Ordered接口方式设置顺序
 */
@Aspect
@Component
public class AnnoOrderAspect2 implements Ordered {
    /**
     * 切入点,该切入点匹配service包下所有类所有方法
     */
    @Pointcut("execution(* com.itan.aop.service..*.multiply(..))")
    public void pointCut() {}

    /**
     * 前置通知
     */
    @Before(value = "pointCut()")
    public void before() {
        System.out.println("AnnoOrderAspect2前置通知");
    }

    /**
     * 后置通知
     */
    @AfterReturning(value = "pointCut()", returning = "result")
    public void afterReturning(Object result) {
        System.out.println("AnnoOrderAspect2后置通知,返回值为:" + result);
    }

    /**
     * 最终通知
     */
    @After(value = "pointCut()")
    public void afterFinally() {
        System.out.println("AnnoOrderAspect2最终通知");
    }

    /**
     * 获取顺序值
     * @return
     */
    @Override
    public int getOrder() {
        return Integer.MAX_VALUE - 1;
    }
}
@Test
public void test05() {
    // 通过配置文件创建容器对象
    ApplicationContext context = new AnnotationConfigApplicationContext(AopConfig.class);
    CalculateService calc = context.getBean(CalculateService.class);
    System.out.println(calc.getClass());
    calc.multiply(2,3);
}
/**
 * 运行结果:值越小的切面的前置通知越先执行,后置通知越后执行
 * AnnoOrderAspect1前置通知
 * AnnoOrderAspect2前置通知
 * AnnoOrderAspect2后置通知,返回值为:6
 * AnnoOrderAspect2最终通知
 * AnnoOrderAspect1后置通知,返回值为:6
 * AnnoOrderAspect1最终通知
 */
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

5、基于注解的AOP配置 的相关文章

  • elasticsearch 后置过滤器(Post Filter)

    本章翻译自Elasticsearch官方指南的Filtering Queries and Aggregations一章 过滤查询以及聚合 A natural extension to aggregation scoping is filte
  • AC-DC--------单相可控整流电路

    带电阻负载的工作情况 原理图 波形图 在分析整流电路工作时 认为晶闸管 开关器件 为理想器件 即晶闸管导通时其管压降等于零 晶闸管阻断时其漏电流等于零 除非特意研究晶闸管的开通 关断过程 一般认为晶闸管的开通与关断过程瞬时完成 工作原理 改
  • 基本流程图与跨职能流程图

    流程可以用流程图来表示 但它们有一个缺点 标准流程图无法表明谁负责这些活动 流程可以用流程图来表示 但它们有一个缺点 标准流程图无法表明谁负责这些活动 因此 跨职能流程图 或称为泳道图 泳道流程图 跨职能流程图 通过定义谁做什么来使流程更加
  • Ajax中get请求和post请求的区别

    Ajax中请求方式有get和post两种 二者的区别可以从传参方式 请求头以及参数类型来进行比较 post请求 get请求 区别 1 传参方式 get请求在url的尾部传递参数 而post请求在send方法中传递参数 2 请求头 post请
  • java解析邮件并下载附件

    package com testspring mailserver mail parsemail import com sun mail pop3 POP3Folder import org springframework web bind
  • 配置EPEL 源

    EPEL Extra Packages for Enterprise Linux 是由 Fedora Special Interest Group 为企业 Linux 创建 维护和管理的一个高质量附加包集合 适用于但不仅限于 Red Hat
  • Spring Boot中禁用Jackson的科学计数法的序列化与反序列化

    application properties spring jackson deserialization USE BIG DECIMAL FOR FLOATS true spring jackson serialization WRITE
  • (40)[ICCV15] Fast R-CNN

    计划完成深度学习入门的126篇论文第四十篇 微软的Ross Girshick研究的Obeject Detection的模型 github Abstract 提出了一种基于区域卷积网络的快速目标检测方法 Fast R CNN Fast R C
  • ChatGPT在编程方面的用例:节省时间并提高工作效率

    除非您一直住在树林里的小屋里 远离电网 否则您可能听说过ChatGPT AI 聊天机器人于 2022 年 11 月发布并引起了不小的轰动 这引出了一个问题 这项激动人心的新技术究竟能为您 您的企业和您的行业做什么 ChatGPT 在各个领域
  • 山洪灾害监测预警系统解决方案

    一 方案背景 山洪灾害是指山丘地区由降雨引起的洪水 泥石流和滑坡灾害 近年来 我国突发性 局部性极端强降雨引发的山洪灾害导致大量人员伤亡 占洪涝灾害死亡总人数的比例趋上升趋势 群死群伤事件时有发生 山洪灾害严重制约山区和丘陵地区经济发展 人
  • webpack

    一 背景 随着前端的项目逐渐扩大 必然会带来的一个问题就是性能 尤其在大型复杂的项目中 前端业务可能因为一个小小的数据依赖 导致整个页面卡顿甚至奔溃 一般项目在完成后 会通过webpack进行打包 利用webpack对前端项目性能优化是一个
  • Spring源码深度解析:三、容器的刷新 - refresh()

    一 前言 文章目录 Spring源码深度解析 文章目录 我们先通过Spring源码的整体流程 来了解Spring的工作流程是什么 接着根据这个工作流程一步一步的阅读源码 二 Spring容器的启动 public class Test pub
  • QT页面旋转涉及源码修改

    QT页面旋转涉及源码修改 qlinuxfbscreen cpp qlinuxfbscreen h qt页面旋转 在源码中直接搜索这两个文件名称 直接替换内容即可 qlinuxfbscreen cpp Copyright C 2016 The
  • Mongo进阶--存储原理

    存储引擎 Storage wiredTiger引擎 3 0新增引擎 官方宣称在read insert和复杂的update下具有更高的性能 所以后续版本 我们建议使用wiredTiger 所有的write请求都基于 文档级别 的lock 因此
  • GitHub 供应链安全已支持 Dart 开发者生态

    通过 Dart 和 GitHub 团队的共同努力 自 10 月 7 日起 GitHub 的 Advisory Database 安全咨询数据库 Dependency Graph 依赖项关系图 和 Dependabot 依赖更新机器人 开始支
  • MySQL 时间减法

    select date sub curdate interval 1 SECOND 减一秒 select date sub curdate interval 1 MINUTE 减一分钟 select date sub curdate int
  • linux远程telnet和ss都连不上,CentOS7 可以ping通 但是telnet无法连接上端口的问题

    在一台全新的Linux上部署项目 遇到了一些问题 1 安装zookeeper 启动成功 正常运行 本地通过telnet无法连接到zookeeper 可能原因 1 可能是端口没有起来 通过ss ntl可以清楚看到 2181端口已经启动 起来了
  • P1005 最大公约数

    算法 欧几里得辗转相除法 include
  • 文件包含 78-79

    web78 没有什么绕过 file php filter convert base64 encode resource flag php构建这个伪协议之后可以得到flag 首先这是一个file关键字的get参数传递 php 是一种协议名称

随机推荐

  • 2020年中国研究生数学建模竞赛B题

    降低汽油精制过程中的辛烷值损失模型 一 背景 汽油是小型车辆的主要燃料 汽油燃烧产生的尾气排放对大气环境有重要影响 为此 世界各国都制定了日益严格的汽油质量标准 见下表 汽油清洁化重点是降低汽油中的硫 烯烃含量 同时尽量保持其辛烷值 欧盟和
  • JavaScript的一些设计原则

    1 单一职责原则 SRP 单一职责原则通常指 一个类只有一种功能 但是JavaScript是一门面向对象的语言 没有类的概念 所以单一职责在JavaScript中的含义是 一个对象 方法 只有一种功能 那么为什么需要单一职责原则呢 是因为不
  • 「Web3大厂」价值70亿美元的核心竞争力

    经过近 5 年的研发和酝酿 Linea 团队在 7 月的巴黎 ETHCC 大会期间宣布了主网 Alpha 的上线 引起了社区的广泛关注 截止 8 月 4 日 据 Dune 数据信息显示 其主网在一周内就涌入了 100 多个生态项目 跨入了超
  • 远程桌面链接怎么用(win10电脑远程桌面连接工具怎么使用)

    相信很多人都已经使用过QQ的远程协助 远程协助功能可以实现好友间桌面共享 还可以让好友操作自己的电脑 帮助解决一些电脑问题 然而 很多人却忽略了Windows本身就附带的一个功能 远程桌面连接 其实它的功能 性能等一点都不弱 而且它比很多第
  • 融云荣获「2023 中国数字生态通信领军企业」奖

    融云北极星如何协助开发者排查问题和预警风险 8月17日直播课 点击上方报名 由 B P 商业伙伴主办的 2023 数字生态大会 于 8 月 4 日在京举行 融云携数智办公解决方案受邀参展 并获 2023 中国数字生态通信领军企业 奖 关注
  • 微信H5页面背景音乐自动播放

    移动端默认是禁止背景音乐自动播放的 很多需求都需要在页面加载完成的情况下同时出现背景音乐 基于微信的H5页面的音频自动播放的方法网上有很多教程 本次分享的只是一种思路
  • angular 单元测试jest

    前言 最近公司要求笔者开发编写项目单元测试 之前使用过angular框架 但是不知道原来在生成组件的时候多的内个文件 name spec ts 是用来编写angular的单元测试的 下面简单介绍一下关于单元测试的一些问题 单元测试代码和业务
  • java基础:初始化块

    初始化块 1 什么是初始化块 初始化块是java类中可出现的第四种成员 成员变量 方法 构造器 一个类中可以有多个初始化块 2 初始化块的作用 从某种程度来看 初始化块是构造器的补充 初始化块总是在构造器执行之前执行 系统通压根可以使用初始
  • CUDA 初体验

    CUDA Visual Profiler CUDA编程指导 shared memory Page locked out memory C CUDA 调用 CUDA 编程介绍 CUDA 数据同步 CUDA Visual Profiler 在上
  • 关于静态批处理/动态批处理/GPU Instancing /SRP Batcher的详细剖析

    静态批处理 1 定义 标明为 Static 的静态物件 如果在使用相同材质球的条件下 在Build 项目打包 的时候Unity会自动地提取这些共享材质的静态模型的Vertex buffer和Index buffer 根据其摆放在场景中的位置
  • 刷脸支付成众多创业者青睐的项目

    风口正盛 优势尽显 刷脸支付成了众多投资者与创业者青睐的项目 布局刷脸支付行业 快速抢占头部市场 支付机构是供给方 商家B端和用户C端是需求方 而中间ISV服务商的作用就至关重要了 虽然未来存在很多变数 但刷脸支付的趋势不可阻挡 用户使用比
  • 《caffe学习之路》第五章:Ubuntu16.04 caffe ssd 在QT环境上编译运行ssd_detect.cpp

    大多深度学习框架主要支持python 而caffe提供c 接口 这也是我选择caffe框架的原因 前一章说到examples ssd目录下的ssd detect cpp文件是weiliu等大神给我们提供的 算是一个c 实现demo 这一章主
  • 如何在UE4里面打开一个Windows窗口

    案例 FailureMessage FText Format LOCTEXT PrimaryGameModuleCouldntBeLoaded The game module 0 could not be loaded There may
  • mac m2 安装使用linux

    问题出现在哪里
  • 图片转为git 小程序 python

    先展示效果图 下面展示一些 内联代码片 import os import imageio from natsort import natsorted def create gif image list gif name frames for
  • android 平板怎么刷机,小白必看,安卓平板电脑刷机教程之一键刷机

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 从来没刷机的的小白 你有以下疑问吗 什么是 刷机 什么是 ROM 什么是 ROOT 什么是 Recovery 什么是USB调试模式 如何打开USB调试模式 刷机会不会损坏我的设备 刷机中途能拔掉
  • 利用反射创建对象

    public class Reflection public static void main String args throws Exception Reflection reflection new Reflection System
  • HTML属性

    目录 HTML 属性 属性实例 更多 HTML 属性实例 属性例子 1 属性例子 2 属性例子 3 HTML 提示 使用小写属性 始终为属性值加引号 HTML 属性参考手册 一个完整的实例 属性为 HTML 元素提供附加信息 HTML 属性
  • 安装Firefly错误-Unable to find vcvarsall.bat

    晚上尝试安装Firefly时 在安装twisted时出现错误而退出 根据错误提示如下 error Setup script exited with error Microsoft Visual C 9 0 is required Unabl
  • 5、基于注解的AOP配置

    一 开启注解支持 1 概述 1 Spring AOP如同IoC一样支持基于XML和基于注解两种配置方式 基于注解所需的依赖和基于XML所需的依赖一致 其中spring context包含了Spring IoC Spring AOP等核心依赖