写点什么

【Spring 学习笔记 (十一)】基于注解的 Spring AOP

作者:倔强的牛角
  • 2022 年 6 月 16 日
  • 本文字数:2638 字

    阅读完需:约 9 分钟

【Spring 学习笔记(十一)】基于注解的Spring AOP

写在前面😘

大一电子信息工程新生,请多多关照,希望能在 InfoQ 社区记录自己的学习历程!

【Spring 学习笔记】 系列教程基于 Spring 5.2.10.RELEASE讲解。

一、AOP 简介

前面说过,Spring 的核心思想就是 IoC 和 AOP,有关 IoC 的内容已经介绍过一部分了,接下来就来讲下 Spring 另一大重点:AOP

1、什么是 AOP

AOP ,“Aspect Oriented Programming”,译为“面向切面编程”,和 OOP(面向对象编程)类似,它也是一种编程思想

2、AOP 的作用(特点)

代理模式

Spring AOP 的实现原理是代理模式,AOP 的作用是通过代理类为原始类增加一些额外功能:如日志管理、权限管理、事务管理、异常管理等一些非业务性功能

无入侵式

与传统的公共方法不同,Spring AOP 并不是直接调用的,AOP 是通过横向的抽取机制实现的。它将一些非业务的通用功能抽取出来单独维护,并通过配置文件或注解的形式定义这些功能要以哪种方式作用在哪个模块中,可以在无须修改任何业务代码的基础上完成对这些通用功能的调用和修改,即无入侵式的。

解耦合

事务与非事务功能分离,Spring AOP 还减少代码的重复,让我们更专注于专注业务逻辑代码。

3、AOP 相关的专业术语

4、AOP 框架

目前最流行的 AOP 实现(框架)主要有两个,分别为 Spring AOPAspectJ


  • 注:一般这两个框架一起整合使用。


二、AOP 入门案例

SpringAOP 的开发有两种方式,XML 和 注解, 本篇文章及之后的教程都使用注解开发演示.

1、添加 AOP 依赖

pom.xml文件里添加 Spring AOP AspectJ 的 jar 包依赖


  • Spring AOP 使用纯 Java 实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码。

  • AspectJ 是一个基于 Java 语言的 AOP 框架。从 Spring2.0 开始,Spring AOP 引入对 Aspect 的支持,AspectJ 扩展了 Java 语言,提供了一个专门的编译器,在编译时提供横向代码的织入。


<dependencies>    <!--包含Spring AOP:有基本的AOP功能-->    <dependency>        <groupId>org.springframework</groupId>        <artifactId>spring-context</artifactId>        <version>5.2.10.RELEASE</version>    </dependency>    <!--AspectJ框架有更强大的AOP功能-->    <dependency>        <groupId>org.aspectj</groupId>        <artifactId>aspectjweaver</artifactId>        <version>1.9.5</version>    </dependency></dependencies>
复制代码


可以看到spring-context中已经导入了spring-aop,所以不需要再单独导入spring-aop


2、创建目标接口和实现类

目标接口和实现类就是所谓的 Target(目标),即要被代理的对象。


/*UserDao接口*/public interface UserDao {    public void add();    public void delete();    public void update();    public void select();}/*UserDaoImpl实现类*/@Repositorypublic class UserDaoImpl implements UserDao {    @Override    public void add() {        System.out.println("正在执行 UserDao 的 add 方法");    }    @Override    public void delete() {        System.out.println("正在执行 UserDao 的 delete 方法");    }    @Override    public void update() {        System.out.println("正在执行 UserDao 的 update 方法");    }    @Override    public void select() {        System.out.println("正在执行 UserDao 的 select 方法");    }}
复制代码

3、创建切面类(通知类)

3.1 定义切面 @Aspect

通过 @Aspect 注解将一个 Bean 定义为切面。


@Component//将这个类定义成 Bean@Aspect//将这个Bean定义为切面public class MyAdvice {}
复制代码

3.2 定义切点 @Pointcut

在 AspectJ 中,我们可以使用 @Pointcut 注解用来定义一个切点。


//切点方法必须是private,无返回值,无参数@Pointcut(value ="execution(* com.bighorn.*.*Dao.*(..))")private void pointCut() {}
复制代码


注意:


  • 定义为切点的方法是一个无意义的 private 方法,即无参数、无返回值(void)、无方法体

  • @Pointcut 注解中有一个 value 属性,这个属性的值就是切入点表达式(插个眼在这,下篇文章详细嗦嗦)

3.3 定义通知

**通知(Advice)**就是将共性功能抽取出来后形成的方法,即对切入点增强的内容


通知有很多类型:前置通知、后置通知、环绕通知、异常通知、返回通知。(插个眼在这,下篇文章详细嗦嗦)


通知注解中有一个 value 属性,value 属性的取值就是这些通知(Advice)所要织入(Weaving)切点(PointCut),它既可以是切入点表达式,也可以是切入点引用(切入点对应的方法名称)


//使用切入点引用@Before("MyAdvice.pointCut()")public void beforeAdvice() {    System.out.println("这是前置通知……");}//使用切入点表达式@After(value ="execution(* com.bighorn.*.*Dao.*(..))")public void afterAdvice(){    System.out.println("这是后置通知……");}
复制代码

3.4 切面类完整代码

/*切面类(通知类)*/@Component//将这个类定义成 Bean@Aspect//将这个Bean定义为切面public class MyAdvice {    //切点方法必须是private,无返回值,无参数    @Pointcut(value = "execution(* com.bighorn.*.*Dao.*(..))")    private void pointCut() {    }
//使用切入点引用 @Before("MyAdvice.pointCut()") public void beforeAdvice() { System.out.println("这是前置通知……"); } //使用切入点表达式 @After(value ="execution(* com.bighorn.*.*Dao.*(..))") public void afterAdvice(){ System.out.println("这是后置通知……"); }}
复制代码

4、启用 @AspectJ 注解支持

在 Spring 的配置类中使用@AspectJ 注解开启 AspectJ 的自动代理,使用 @ComponentScan 注解开启注解扫描。


/*Spring核心配置类*/@Configuration@ComponentScan("com.bighorn") //开启注解扫描@EnableAspectJAutoProxy //开启 AspectJ 的自动代理public class SpringConfig {}
复制代码

5、编写运行程序

public static void main(String[] args) throws SQLException {    //获取配置类初始化容器    ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);    //从容器中获取UserDao对象    UserDao userDao = context.getBean(UserDao.class);    //调用userDao的方法    userDao.add();    userDao.delete();    userDao.update();    userDao.select();}
复制代码


运行结果如下,可以发现对每个方法都进行的加强:前置通知和后置通知


写在后面🍻

感谢观看啦✨

有什么不足,欢迎指出哦💖

发布于: 2022 年 06 月 16 日阅读数: 29
用户头像

把学问造就,还期身健行优。 2022.06.02 加入

大一在读,电子信息工程专业。 希望在InfoQ写作社区记录自己的学习历程!

评论

发布
暂无评论
【Spring 学习笔记(十一)】基于注解的Spring AOP_Java_倔强的牛角_InfoQ写作社区