【Spring】AOP思想

一、前言

这篇文章主要介绍spring中AOP相关的知识。

二、内容

1.AOP简介

AOP概念

AOP是面向切面编程(Aspect Oriented Programming)的简写,就像我们之前学习过面向对象编程(OOP,Object Oriented Programming),同样是一种程序设计思想,其作用是,在无需修改代码的前提下,对业务增加统一的功能,比如日志记录,权限控制,事务管理等,使得代码更加解耦,提高开发效率

基本思想

连接点:在spring中连接点可以指某个类中所有的方法
切入点:类中需要做功能增强的方法
通知:包含功能增强的代码的方法
通知类:通知所在的类
切面:建立切入点与通知之间的联系

AOP涉及到的基本概念

基本概念

2.AOP入门案例

步骤

1.准备工作(事先准备好dao和实现类)

dao接口

dao的实现类

2.导入AOP相关依赖

<!--        AOP相关依赖-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.6</version>
        </dependency>
        <!--        spring框架(包含了spring-aop)-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>

3.使用@Component和@Aspect编写通知类(切面类)

通知类

4.使用@PointCut在方法壳上定义切入点(实际是方法)

定义切入点

5.使用@Before/@After注解定义切面

定义切面

6.使用@EnableAspectJAutoProxy注解告知SpringConfig类开启AOP支持

开启AOP支持
7.运行主类查看结果

主类

运行结果

由此可见,在insert()方法执行前执行了通知,AOP执行成功。

3.AOP执行流程

1.spring容器启动

2.读取切面中的切入点方法

spring读取切入点

3.初始化bean,并判断bean中的方法是否匹配到切入点

(1)匹配成功

主类

运行结果:

匹配成功

(2)匹配失败

匹配失败

运行结果:

运行结果

4.总结:

AOP执行流程

4.切入点表达式

1.标准格式

在这里插入图片描述

2.使用通配符* … +

使用通配符

举例:

(1)使用*

单个通配符

(2)使用…

使用..

(3)使用+

使用+

3.书写规范

切入点表达式书写规范

5.通知类型

首先准备好了dao-BookDao和实现类BookDaoImpl,以及通知类Advice

public interface BookDao {
    void insert();
    int select();
}
@Repository
public class BookDaoImpl implements BookDao {
    @Override
    public void insert() {
        System.out.println("book dao insert ...");
//        int i = 1/0;
    }

    @Override
    public int select() {
        System.out.println("book dao select ...");
        return 68;
    }
}

为两个方法定义好了切入点

	@Pointcut("execution(void demo7.dao.BookDao.insert())")
    private void fn1() {
    }

    @Pointcut("execution(int demo7.dao.BookDao.select())")
    private void fn2() {
    }
前置通知@Before

前置通知

主类

运行结果:

运行结果

后置通知@After

和前置通知类似,只是在原始方法执行后执行通知,下面直接来看运行结果

后置通知

运行结果:

运行结果

环绕通知@Around

环绕通知

运行结果:

运行结果

注意事项:

注意事项
1.环绕通知必须有ProceedingJoinPoint类型的方法形参,用于执行原始方法
2.如果没有这个形参,原始方法不执行
3.由于未知原始方法是否会抛异常,因此这个切面方法必须抛异常
4.如果原始方法有返回值,切面方法的返回值必须是Object类型
5.如果原始方法是void类型,切面方法也可以是Object类型
返回后通知@AfterReturning

返回后通知

运行结果:

运行结果

@After和@AfterReturning对比

@After@AfterReturning
原始方法发生异常时仍然通知原始方法正常return才通知
抛出异常后通知@AfterThrowing


异常通知

运行结果:

运行结果

6.案例:使用@Around统计业务层方法执行时间

1.准备工作

准备工作
准备好了实体类,mapper接口和service和和实现类,以及三个配置文件和jdbc.properties文件,下面是通知类(使用Signature类获取执行的方法有关信息

@Component
@Aspect
public class Advice {

    // 为两个方法设置切入点
    @Pointcut("execution(* demo8.service.*Service.select*(..))")
    private void selectPt() {
    }

    // 设置切面
    @Around("selectPt()")
    public Object method(ProceedingJoinPoint point) throws Throwable {
        Signature signature = point.getSignature();
        String methodName = signature.getName(); // 获取方法名
        String typeName = signature.getDeclaringTypeName(); // 获取方法类型
        long startTime = System.currentTimeMillis(); // 获取执行前的系统时间
        Object o = null;
        for (int i = 0; i < 1000; i++) {
            o = point.proceed();
        }
        long endTime = System.currentTimeMillis(); // 获取执行后的系统时间
        System.out.println("执行"+typeName+"类型的"+methodName+"方法花费时间:" + (endTime - startTime) + "ms");
        return o;
    }
}

测试类:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class UserServiceTest {

    @Autowired
    private UserService service;

    @Test
    public void testSelectAll() {
        List<User> users = service.selectAll();
        System.out.println(users);
        System.out.println(users.size());
        // 获取方法有关信息
    }

    @Test
    public void testSelectById() {
        User user = service.selectById(2);
        System.out.println(user);
    }
}

测试结果:
运行结果

7.AOP获取通知数据

获取方法参数

五种通知都可以获取方法参数,一般使用JoinPoint类型形参的getArgs()方法,在环绕通知中(@Around)使用ProceedJoinPoint类型的getArgs()方法。

举例:
(1)JoinPoint对象

@Before("fn1()")
    public void before(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs(); // 1.前置通知获取切入点方法参数
        System.out.println(Arrays.toString(args));
        System.out.println("before ...");
    }

业务层接口和实现类:
接口

实现类

主类和运行结果:

在这里插入图片描述

(2)ProceedJoinPoint对象

ProceedJoinPoint对象

获取方法返回值

只有返回后通知@AfterReturning和环绕通知@Around可以获取

(1)环绕通知

环绕通知

(2)返回后通知

使用Object类型的方法形参,并在注解上加returning = 形参名称

返回后通知

获取异常信息

只有抛出异常后通知@AfterThrowing和环绕通知@Around可以获取

(1)环绕通知

首先在serviceImpl抛出一个异常

在这里插入图片描述

捕获异常

(2)抛出异常后通知

使用Throwable 类型的形参,并在注解上加上throwing = 形参名称

获取异常对象

8.案例:使用@Around处理参数中的字符串

需求

去除前后空格

运行结果

在这里插入图片描述

9.AOP总结:

这篇文章主要介绍了AOP面向切面编程的概念和作用,以及切入点、通知、切面的内容,后面介绍通知的类别(5类),最后介绍在通知中如何获取并处理数据。

三、结语

AOP是spring的核心思想之一,前面学习了IOC(控制反转),至此开始越来越了解spring的工作机制。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

向阳花花花花

感谢大佬支持,本人会继续努力哒

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值