Spring AOP的注解配置

(一)简述

上回我们说到了spring AOP的实现原理,我们发现其实通过自己编程来实现这个功能还是非常繁琐的。spring因此给我们提供了相应的配置方式,从而帮助我们简化开发过程,使我们的注意力能充分关注在业务逻辑上。

在了解AOP的注解配置之前,我们先要来关注一下AOP中的一些专业术语:

Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点。
Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义。
Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知,通知分为:前置通知,后置通知,异常通知,最终通知,环绕通知。
Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下,Introduction可以在运行期为类动态地添加一些方法或Field。
Target(目标对象):代理的目标对象。
Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。
Proxy(代理):一个类被AOP织入增强后,就产生一个代理类。
Aspect(切面): 是切入点和通知的结合。

我们来看一下这些概念,我们只需要记住几个点。首先是切面的概念,也就是AOP中的A(Aspect),他是切入点和通知的结合,通俗的讲,就是程序被附加的功能和这个功能附加的位置。切入点是通知切入的位置,而连接点就是可以作为切入点的位置(但不一定被切入)。通知,更好的理解应该把他称为增强,就是我们要附加的功能(比如写日志的功能),这是面向切面编程的核心。我们来理一下刚刚讲了哪几个关键点,连接点、切入点、通知、切面。

在这里插入图片描述

本次文章中,我们会讲基于@Aspect的注解配置方式,而不是传统的XML配置方式。因为XML的配置过于繁琐且不好理解,而注解配置方式更加通俗易懂。不过,弄懂的前提是要充分理解上面的几个概念,因为这会与后面的注解的选择息息相关。

(二)简单实例

我们来看一下一个简单的例子来研究一下AOP具体应该怎么配置。首先我们先要导入依赖,我们得在pom.xml文件中添加依赖:

<dependency>
	<groupId>org.aspectj</groupId>
  	<artifactId>com.springsource.org.aspectj.weaver</artifactId>
  	<version>1.6.4.RELEASE</version>
</dependency>

这是使用@Aspect注解需要的依赖,当然还需要一些spring框架的依赖,这里我就不写上去了。

然后要写配置文件,这里主要是要添加AOP的命名空间和约束,并且开启@AspectJ注解配置方式:

<?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:bean="http://www.springframework.org/schema/context"
       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/context
       https://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd"
       xmlns:aop="http://www.springframework.org/schema/aop">

    <aop:aspectj-autoproxy/>
    <context:component-scan base-package="com.test"/>
</beans>

编写核心方法,也就是我们将要被切入的方法:

package com.test;

import org.springframework.stereotype.Component;

@Component("Hello")
public class Hello {
    void sayHello(String s){
        System.out.println("hello " + s);
    }
}

然后编写切面,这是最关键的部分。前面说过,切面分为两个部分,一个是切入点,另一个是通知。首先,我们要给切面类上加上@Aspect注解,表示这是一个切面(注意:只有已经被IOC容器收录的Bean对象才能加@Aspect注解)。然后编写我们的通知方法,也就是我们需要附加的功能,在这里指的是before和after方法。光有方法肯定是不行的,我们需要给方法添加注解,让spring知道这是一个通知。描述通知类型一共有五个注解:

在这里插入图片描述
这五个注解分别对应了五种通知方式:前置通知,后置通知,最终通知,异常通知,环绕通知。这些其实是代表通知的时机,大家可以都去尝试一下分别有什么作用。光有通知时机还不够,还需要具体切入的位置(切入点),这就是注解中字符串的作用。这段字符串的专业术语叫指示器,我们来看看一共有多少种指示器:

在这里插入图片描述

我们最常用的就是execution()这个指示器,代表方法的执行,其中指示器的参数要填写全类名+方法名来确定一个方法,有需要也可以加上返回值和参数等等。我们这个案例中填写的就是全类名+方法名,这样才能在一个项目中唯一的定位一个方法。这也就很明显的展现了一个原则:只有方法才能作为切入点,换句话说就是所有的方法都是连接点可以被切入。

package com.test;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component("Logger")
public class Logger {
    @Before("execution(* com.test.Hello.sayHello(..))")
    void before(){
        System.out.println("before hello");
    }

    @After("execution(* com.test.Hello.sayHello(..))")
    void after(){
        System.out.println("after hello");
    }
}

这样我们就可以总结出AOP配置的公式:XX通知(五种通知类型之一,用注解配置)在XX处(通知类型注解中的字符串)切入了目标方法,执行了XX功能(通知方法,自己定义)。试着和上面的代码对应看看是不是这么回事。

2020年7月30日

Logo

Authing 是一款以开发者为中心的全场景身份云产品,集成了所有主流身份认证协议,为企业和开发者提供完善安全的用户认证和访问管理服务

更多推荐