面向切面AOP

AOP思想实际上就是:在运行时,动态地将代码切入到类的指定方法、指定位置上.也就是说,我们可以使用AOP来帮助我们在方法执行前或执行之后,做一些额外的操作,实际上,就是代理!

通过AOP我们可以在保证原有业务不变的情况下,添加额外的动作。比如我们的某些方法执行完成之后,需要打印日志,那么这个时候,我们就可以使用AOP来帮助我们完成,它可以批量地为这些方法添加动作。可以说,它相当于将我们原有的方法,在不改变源代码的基础上进行了增强处理。

相当于我们的整个业务流程,被直接斩断,并在断掉的位置添加了一个额外的操作,再连接起来,也就是在一个切点位置插入内容。它的原理实际上就是通过动态代理机制实现的,Spring底层并不是使用的JDK提供的动态代理,而是使用的第三方库实现,它能够以父类的形式代理,而不是接口。

使用SpringAOP

先导入一个依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.3.13</version>
</dependency>

明确实现AOP操作需要知道这些内容

1. 需要切入的类,类的哪个方法需要被切入

2. 切入之后需要执行什么动作

3. 是在方法执行前切入还是在方法执行后切入

4. 如何告诉Spring需要进行切入

找到需要切入的类

public class Student {
    String name;
    int age;

		//分别在test方法执行前后切入
    public int test(String str) {
        System.out.println("我是一个测试方法:"+str);
        return str.length();
    }
}

定义方法执行前后我们要执行的操作

public class AopTest {

    //执行之后的方法
    public void after(){
        System.out.println("我是执行之后");
    }

    //执行之前的方法
    public void before(){
        System.out.println("我是执行之前");
    }
}

@Before

前置通知:目标方法之前执行

@After

后置通知:目标方法之后执行(始终执行)

@AfterReturning

返回通知:执行方法结束前执行(异常不执行)

@AfterThrowing

异常通知:出现异常的时候执行

@Around

环绕通知:环绕目标方法执行

将要进行AOP操作的类注册为Bean

<bean name="student" class="com.test.bean.Student"/>
<bean name="aopTest" class="com.test.aop.AopTest"/>

一个是Student类,还有一个就是包含我们要切入方法的AopTest类,注册为Bean后,他们就交给Spring进行管理,这样Spring才能帮助我们完成AOP操作

修改顶部,引入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: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/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

使用`aop:config`来添加一个新的AOP配置

<aop:config>

   

</aop:config>

告诉Spring,我们要切入的是哪一个类的哪个或是哪些方法

<aop:pointcut id="test" expression="execution(* com.test.bean.Student.test(String))"/>

`expression`属性的`execution`填写格式如下

修饰符 包名.类名.方法名称(方法参数)

* 修饰符:public、protected、private、包括返回值类型、static等等(使用*代表任意修饰符)

* 包名:如com.test(*代表全部,比如com.*代表com包下的全部包)

* 类名:使用*也可以代表包下的所有类

* 方法名称:可以使用*代表全部方法

* 方法参数:填写对应的参数即可,比如(String, String),也可以使用*来代表任意一个参数,使用..代表所有参数。

也可以使用其他属性来进行匹配,比如`@annotation`可以用于表示标记了哪些注解的方法被切入

为此方法添加一个执行前动作和一个执行后动作

<aop:aspect ref="aopTest">
    <aop:before method="before" pointcut-ref="test"/>
    <aop:after-returning method="after" pointcut-ref="test"/>
</aop:aspect>

配置完成

public static void main(String[] args) {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("test.xml");
    Student student = context.getBean(Student.class);
    student.test("lbwnb");
}

方法执行前后,分别调用了我们对应的方法。但是仅仅这样还是不能满足一些需求,在某些情况下,我们可以需求方法执行的一些参数,比如方法执行之后返回了什么,或是方法开始之前传入了什么参数等等。

这个时候,我们可以为我们切入的方法添加一个参数,通过此参数就可以快速获取切点位置的一些信息

//执行之前的方法
public void before(JoinPoint point){
    System.out.println("我是执行之前");
    System.out.println(point.getTarget());  //获取执行方法的对象
    System.out.println(Arrays.toString(point.getArgs()));  //获取传入方法的实参
}

通过添加JoinPoint作为形参,Spring会自动给我们一个实现类对象,这样我们就能获取方法的一些信息了。

环绕方法相当于完全代理了此方法,它完全将此方法包含在中间,需要我们手动调用才可以执行此方法,并且我们可以直接获取更多的参数

编写实现环绕的方法,通过`proceed`方法来执行代理的方法

public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("方法开始之前");
    Object value = joinPoint.proceed();
    System.out.println("方法执行完成,结果为:"+value);
    return value;
}

修改xml

<aop:aspect ref="aop">
    <aop:pointcut id="after" expression="execution(* com.cafuc.bean.Student.say(String,int ))"/>
    <aop:around method="around" pointcut-ref="after"/>
</aop:aspect>

使用接口实现AOP

首先我们需要将一个类实现Advice接口,只有实现此接口,才可以被通知,比如我们这里使用`MethodBeforeAdvice`表示是一个在方法执行之前的动作

public class AopTest implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("通过Advice实现AOP");
    }
}

args代表的是方法执行前得到的实参列表,还有target表示执行此方法的实例对象

修改xml

<aop:config>

    <aop:pointcut id="stu" expression="execution(* com.test.bean.Student.say(String))"/>

    <aop:advisor advice-ref="before" pointcut-ref="stu"/>

</aop:config>

`AfterReturningAdvice`就需要实现一个方法执行之后的操作

public class AopTest implements MethodBeforeAdvice, AfterReturningAdvice {
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("我是方法执行之后!");
    }
}

AOP 领域中的特性术语

- 通知(Advice): AOP 框架中的增强处理,通知描述了切面何时执行以及如何执行增强处理,也就是我们上面编写的方法实现。

- 连接点(join point): 连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出,实际上就是我们在方法执行前或是执行后需要做的内容。

- 切点(PointCut): 可以插入增强处理的连接点,可以是方法执行之前也可以方法执行之后,还可以是抛出异常之类的。

- 切面(Aspect): 切面是通知和切点的结合,我们之前在xml中定义的就是切面,包括很多信息。

- 引入(Introduction):引入允许我们向现有的类添加新的方法或者属性。

- 织入(Weaving): 将增强处理添加到目标对象中,并创建一个被增强的对象,我们之前都是在将我们的增强处理添加到目标对象,也就是织入

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值