源码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. QWidget居中显示(qt窗口坐标原点是在”左上角”的,有图)

    转载请说明出处, 并附上原文链接http://blog.csdn.net/qq907482638/article/details/72189014. 问题描述 在Qt学习过程中,在让QDialog居中 ...

  2. 关于QWidget和QDialog窗体居中的问题(必须要setFixedSize设初始值大小,否则没法居中)

    最近开发中,遇到了窗体不能居中的问题,看了网上的很多文章,窗口居中,无非都是move至窗口的中心目标; 有两种方式, 一种在构造函数中直接计算中心坐标; 另一种是在窗口show后再move至相应坐标. ...

  3. 2 WCF里面配置的含义

    1 首先介绍所谓的a,b,c. a就是address 地址: b binding 绑定的协议 譬如http  tcp udp 利用这些协议方式请求address: c contract  代表请求的规 ...

  4. Windows下安装MySQL(解压版本)

    解压缩 将下载到的文件解压缩到自己喜欢的位置,例如我自己的位置是D:\Program Files\mysql-5.7.10-winx64 添加环境变量 右键计算机->属性->高级系统设置- ...

  5. wpf 自定义窗口,最大化时覆盖任务栏解决方案

    原文:wpf 自定义窗口,最大化时覆盖任务栏解决方案 相信很多人使用wpf时会选择自定义美观的窗口,因此会设置WindowStyle="None" 取消自带的标题栏.但这样使用 W ...

  6. WPF 获取 ListView DataTemplate 中控件值

    原文:WPF 获取 ListView DataTemplate 中控件值 版权声明:本文为博主原创文章,未经博主允许可以随意转载 https://blog.csdn.net/songqingwei19 ...

  7. ASP.NET Core 项目配置 ( Startup ) - ASP.NET Core 基础教程 - 简单教程,简单编程

    原文:ASP.NET Core 项目配置 ( Startup ) - ASP.NET Core 基础教程 - 简单教程,简单编程 ASP.NET Core 项目配置 ( Startup ) 前面几章节 ...

  8. 王立平--android这四个组成部分

    Android中称为四大组件的为别为:Activity/Service/BroadCast Recevicer/Content  provider Activity:activity是用户和应用程序交 ...

  9. [Android] 环境优化配置Android Studio发展NDK

    ======================================================== 作者:qiujuer 博客:blog.csdn.net/qiujuer 站点:www. ...

  10. C# 自定义泛型类,并添加约束

    using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threa ...