源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all

一、说明

1.1 项目结构说明

  1. 切面配置位于com.heibaiying.config下AopConfig.java文件;
  2. 自定义切面位于advice下,其中CustomAdvice是标准的自定义切面,FirstAdvice和SecondAdvice用于测试多切面共同作用于同一个被切入点时的执行顺序;
  3. OrderService是待切入方法。

1.2 依赖说明

除了spring的基本依赖外,需要导入aop依赖包

 <!--aop 相关依赖-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>${spring-base-version}</version>
</dependency>

二、spring aop

2.1 创建待切入接口及其实现类

public interface OrderService {

    Order queryOrder(Long id);

    Order createOrder(Long id, String productName);
}
public class OrderServiceImpl implements OrderService {

    public Order queryOrder(Long id) {
        return new Order(id, "product", new Date());
    }

    public Order createOrder(Long id, String productName) {
        // 模拟抛出异常
        // int j = 1 / 0;
        return new Order(id, "new Product", new Date());
    }
}

2.2 创建自定义切面类

注:@Pointcut的值可以是多个切面表达式的组合。

/**
 * @author : heibaiying
 * @description : 自定义切面
 */
@Aspect
@Component //除了加上@Aspect外 还需要声明为spring的组件 @Aspect只是一个切面声明
public class CustomAdvice {

    /**
     * 使用 || , or  表示或
     * 使用 && , and 表示与
     * ! 表示非
     */
    @Pointcut("execution(* com.heibaiying.service.OrderService.*(..)) && !execution(* com.heibaiying.service.OrderService.deleteOrder(..))")
    private void pointCut() {

    }

    @Before("pointCut()")
    public void before(JoinPoint joinPoint) {
        //获取节点名称
        String name = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        System.out.println(name + "方法调用前:获取调用参数" + Arrays.toString(args));
    }

    // returning 参数用于指定返回结果与哪一个参数绑定
    @AfterReturning(pointcut = "pointCut()", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        System.out.println("后置返回通知结果" + result);
    }

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕通知-前");
        //调用目标方法
        Object proceed = joinPoint.proceed();
        System.out.println("环绕通知-后");
        return proceed;
    }

    // throwing 参数用于指定抛出的异常与哪一个参数绑定
    @AfterThrowing(pointcut = "pointCut()", throwing = "exception")
    public void afterThrowing(JoinPoint joinPoint, Exception exception) {
        System.err.println("后置异常通知:" + exception);
    }

    @After("pointCut()")
    public void after(JoinPoint joinPoint) {
        System.out.println("后置通知");
    }
}

2.3 配置切面

/**
 * @author : heibaiying
 * @description : 开启切面配置
 */
@Configuration
@ComponentScan("com.heibaiying.*")
@EnableAspectJAutoProxy // 开启@Aspect注解支持 等价于<aop:aspectj-autoproxy>
public class AopConfig {
}

2.4 测试切面

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = AopConfig.class)
public class AopTest {

    @Autowired
    private OrderService orderService;

    @Test
    public void saveAndQuery() {
        orderService.createOrder(1283929319L, "手机");
        orderService.queryOrder(4891894129L);
    }

    /**
     * 多个切面作用于同一个切入点时,可以用@Order指定切面的执行顺序
     * 优先级高的切面在切入方法前执行的通知(before)会优先执行,但是位于方法后执行的通知(after,afterReturning)反而会延后执行
     */
    @Test
    public void delete() {
        orderService.deleteOrder(12793179L);
    }
}

2.5 切面执行顺序

  • 多个切面作用于同一个切入点时,可以用@Order指定切面的执行顺序

  • 优先级高的切面在切入方法前执行的通知(before)会优先执行,但是位于方法后执行的通知(after,afterReturning)反而会延后执行,类似于同心圆原理。

附: 关于切面表达式的说明

切面表达式遵循以下格式:

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)
            throws-pattern?)
  • 除了返回类型模式,名字模式和参数模式以外,所有的部分都是可选的;
  • *,它代表了匹配任意的返回类型;
  • () 匹配了一个不接受任何参数的方法, 而 (..) 匹配了一个接受任意数量参数的方法(零或者更多)。 模式 (*) 匹配了一个接受一个任何类型的参数的方法。 模式 (*,String) 匹配了一个接受两个参数的方法,第一个可以是任意类型,第二个则必须是String类型。

下面给出一些常见切入点表达式的例子。

  • 任意公共方法的执行:

    execution(public * *(..))
    
  • 任何一个以“set”开始的方法的执行:

    execution(* set*(..))
    
  • AccountService 接口的任意方法的执行:

    execution(* com.xyz.service.AccountService.*(..))
    
  • 定义在service包里的任意方法的执行:

    execution(* com.xyz.service.*.*(..))
    
  • 定义在service包或者子包里的任意方法的执行:

    execution(* com.xyz.service..*.*(..))
    
  • 在service包里的任意连接点(在Spring AOP中只是方法执行) :

    within(com.xyz.service.*)
    
  • 在service包或者子包里的任意连接点(在Spring AOP中只是方法执行) :

    within(com.xyz.service..*)
    
  • 实现了 AccountService 接口的代理对象的任意连接点(在Spring AOP中只是方法执行) :

    this(com.xyz.service.AccountService)
    

更多表达式可以参考官方文档:Declaring a Pointcut

附:源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all

spring 5.x 系列第4篇 —— spring AOP (代码配置方式)的更多相关文章

  1. spring 5.x 系列第2篇 —— springmvc基础 (代码配置方式)

    文章目录 一.搭建hello spring工程 1.1 项目搭建 1.2 相关注解说明 二.配置自定义拦截器 三.全局异常处理 四.参数绑定 4.1 参数绑定 4.2 关于日期格式转换的三种方法 五. ...

  2. spring 5.x 系列第18篇 —— 整合websocket (代码配置方式)

    源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all 一.说明 1.1 项目结构说明 项目模拟一个简单的群聊功能,为区分不同的聊 ...

  3. spring 5.x 系列第16篇 —— 整合dubbo (代码配置方式)

    文章目录 一. 项目结构说明 二.项目依赖 三.公共模块(dubbo-ano-common) 四. 服务提供者(dubbo-ano-provider) 4.1 提供方配置 4.2 使用注解@Servi ...

  4. spring 5.x 系列第14篇 —— 整合RabbitMQ (代码配置方式)

    源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all 一.说明 1.1 项目结构说明 本用例关于rabbitmq的整合提供简单消 ...

  5. spring 5.x 系列第12篇 —— 整合memcached (代码配置方式)

    文章目录 一.说明 1.1 XMemcached客户端说明 1.2 项目结构说明 1.3 依赖说明 二.spring 整合 memcached 2.1 单机配置 2.2 集群配置 2.3 存储基本类型 ...

  6. spring 5.x 系列第10篇 —— 整合mongodb (代码配置方式)

    源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all 一.说明 1.1 项目结构说明 配置文件位于com.heibaiying. ...

  7. spring 5.x 系列第17篇 —— 整合websocket (xml配置方式)

    源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all 一.说明 1.1 项目结构说明 项目模拟一个简单的群聊功能,为区分不同的聊 ...

  8. spring 5.x 系列第15篇 —— 整合dubbo (xml配置方式)

    文章目录 一. 项目结构说明 二.项目依赖 三.公共模块(dubbo-common) 四. 服务提供者(dubbo-provider) 4.1 productService是服务的提供者( 商品数据用 ...

  9. spring 5.x 系列第13篇 —— 整合RabbitMQ (xml配置方式)

    源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all 一.说明 1.1 项目结构说明 本用例关于rabbitmq的整合提供简单消 ...

  10. spring 5.x 系列第11篇 —— 整合memcached (xml配置方式)

    文章目录 一.说明 1.1 XMemcached客户端说明 1.2 项目结构说明 1.3 依赖说明 二.spring 整合 memcached 2.1 单机配置 2.2 集群配置 2.3 存储基本类型 ...

随机推荐

  1. 基于Geoserver发布时间地图

    Geoserver它是著名的开源GIS其中软件. 地图服务软件也经常使用的物品.基于geoserver和Openlayers它可以建立一个自由的,开放源码GIS工程. Geoserver公布地图的步骤 ...

  2. QT开发环境的建立以及QTE4.6.3、tslib1.4的移植过程

    1.首先是建立Linux开发环境1.1.在windowsXP下安装博创公司提供的虚拟机软件VMware Workstation,版本为VMware-workstation-full-7.0.1-227 ...

  3. 用acharengine作Android图表

    首先要下载acharengine的包,里面重要的有lib和一些简易的工具,等下我附在文件夹里,而这些包都必须调用的. 然后以下附上主要的作图代码: package org.achartengine.c ...

  4. Leetcode 328 Contains Duplicate set和map应用

    找出数组中重复的数,裸的map和set题 class Solution { public: bool containsDuplicate(vector<int>& nums) { ...

  5. 简明Python3教程 16.标准库

    简介 python标准库作为python标准安装的一部分,其自身包含数量庞大的实用模块, 因此熟悉python标准库非常重要,因为很多问题都能利用python标准库快速解决. 下面我们将研究标准库中的 ...

  6. AdaBoost算法原理及OpenCV实例

    备注:OpenCV版本 2.4.10 在数据的挖掘和分析中,最基本和首要的任务是对数据进行分类,解决这个问题的常用方法是机器学习技术.通过使用已知实例集合中所有样本的属性值作为机器学习算法的训练集,导 ...

  7. Fedora15下搭建QT开发环境及编译QT(提前一键安装完,qt编译所有必需库 yum install gcc-c++ libXtst-devel freetype freetype-devel fontconfig-devel libXrender-devel )

    看了不少linux上编译qt的文章,实际上直接通过yum 安装qt是最方便的,请参考<yum安装qt> 不过初步接触fedora,为了了解一下如何在linux上编译.安装开源代码,所以必须 ...

  8. Node.js 中开源库探秘 object-assign | 全栈之路

    这篇内容呢,讲的是另一个技术栈 Node.js 系列,虽然和咱们这里的主题不是特别吻合,不过嘛,汲取多样性的养分是快速成长的好方法,也是现在流行的全栈工程师的必经之路. 由于这篇内容涉及的是 Node ...

  9. Shell脚本入门学习笔记

    1.shell操作系统和用户之间.负责解释命令行 2./etc/shells 记录登录系统有效支持shell 3./etc/passwd 最后,有人谁可以看到用户的默认shell 4.直接输入shel ...

  10. Bind Enum to Combobox.SelectedIndex

    原文:Bind Enum to Combobox.SelectedIndex Do you mean that you want to bind a variable (not a property) ...