Spring Aop该如何使用

简介: 本文介绍了AOP(面向切面编程)的基本概念和术语,并通过具体业务场景演示了如何在Spring框架中使用Spring AOP。文章详细解释了切面、连接点、通知、切点等关键术语,并提供了完整的示例代码,帮助读者轻松理解和应用Spring AOP。

AOP(Aspect OrientedProgramming),即面向切面编程。本文介绍了AOP的相关概念和术语,用业务场景演示了Spring Aop的使用方式。希望本文对你轻松使用Spring Aop有所帮助。

一 什么是AOP

AOP(Aspect OrientedProgramming),面向切面编程,通过提供另一种思考程序结构的方式来补充面向对象编程(OOP)。OOP中模块化的关键单元是类,而AOP中模块化的单元是方面,即处理过程中某个步骤或阶段。

举个例子,项目中对关键操作需要记录日志,无非是简单地插表操作。但是如果在每个接口中都重复调用或实现,不仅浪费时间,还将项目变得不那么清爽。这时,面向切面编程就该出场了。

利用AOP,可以对项目中边缘业务进行隔离,降低无关业务逻辑耦合度,提高代码复用率和开发效率。一般用于日志记录、性能统计、权限管理、事务控制,异常处理等场景。

二 AOP相关术语

首先来看看AOP的一些术语:

  • 切面(Aspect) :一个关注点。Spring中以注解@Aspect标记在类上,声明一个切面类。
  • 连接点(Joinpoint) :在程序执行过程中某个特定的点,比如调用某方法。
  • 通知(Advice) :定义了切面动作和执行时机,如业务逻辑之外的事务、日志等。
  • 切点(Pointcut) :定义了执行通知的具体地点,是连接点的全集或子集;Spring中使用AspectJ切入点语法。
  • 引入(Introduction) :就是把切面用到目标类中去。在不改变现有类或方法代码的情况下,为其添加新的属性或行为。
  • 目标对象(Target Object) :被一个或者多个切面所通知的对象。Spring AOP是通过运行时代理实现的,因此目标对象是一个被代理类对象。
  • AOP代理(AOP Proxy) :AOP框架创建的对象,用来实现通知的执行。在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。
  • 织入(Weaving) :把切面连接到其它应用程序类型或者对象上,并创建一个被通知的对象。这些可以在编译时、类加载时或运行时完成。Spring AOP框架在运行时完成织入。

三 Spring AOP

Spring最核心的两个功能是Ioc和Aop,即控制反转和面向切面编程。 如官网介绍,AOP在spring中应用如下:docs.spring.io/spring-fram… 即:AOP在Spring框架中用于:

  • 提供声明性企业服务。这类服务中最重要的是声明性事务管理。
  • 让用户实现自定义方面,用AOP补充他们对OOP的使用。

3.1 试用Spring AOP

以下代码可访问:github.com/kqcaihong/a…

3.1.1 准备工作

创建spring boot项目,引入如下依赖。

xml

代码解读

复制代码

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- spring整合aspectj来实现aop -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.18.30</version>
  <scope>provided</scope>
</dependency>

添加启动类及配置application.properties。

java

代码解读

复制代码

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MoreApplication {

  public static void main(String[] args) {
    SpringApplication.run(MoreApplication.class, args);
  }
}

properties

代码解读

复制代码

spring.application.name=aop-demo  
server.port=8010

添加User类。

java

代码解读

复制代码

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class User {

  private Long id;
  private String name;
  private int age;

  public User(String name, int age) {
    this.name = name;
    this.age = age;
  }
}

创建一个UserController类,模拟用户管理业务。

java

代码解读

复制代码

import com.learn.more.entiry.User;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

@RequestMapping("/user")
@RestController
public class UserController implements InitializingBean {

  // 生成ID
  private static final AtomicLong ID_GENERATOR = new AtomicLong(0);
  // 模拟数据库来保存记录
  private static final Map<Long, User> USER_MAP = new ConcurrentHashMap<>();

  // 查询所有用户
  @GetMapping("/queryAll")
  public List<User> queryAll() {
    return USER_MAP.values().stream().sorted(Comparator.comparingLong(User::getId)).collect(Collectors.toList());
  }
  
  // 添加一个用户
  @PostMapping("/add")
  public User addByParam(@RequestParam String name, @RequestParam int age) {
    User user = new User(name, age);
    user.setId(ID_GENERATOR.incrementAndGet());
    USER_MAP.put(user.getId(), user);
    return user;
  }

  // 初始化一条记录
  @Override
  public void afterPropertiesSet() {
    User bob = new User(ID_GENERATOR.incrementAndGet(), "Bob", 33);
    USER_MAP.put(bob.getId(), bob);
  }
}

3.1.2 定义切面

创建AopTest类(交由spring容器管理),使用@Aspect注解声明它是一个切面类,可以在类中定义多个切面。

java

代码解读

复制代码

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Slf4j
@Aspect
@Component
public class AopTest {
}

3.1.3 定义切点

切点通过@Pointcut注解和切点表达式定义。Spring切面最小粒度是方法级别,而execution表达式声明了一个方法要作为切点需要满足的条件。

execution(<修饰符模式>? <返回类型模式> <方法名模式>(<参数模式>) <异常模式>?)

除了返回类型模式、方法名模式和参数模式外,其它项都是可选的。

  • *表示不限制
  • 两个点表示任意参数列表
  • 在多个表达式之间
  • 使用 ||,   or表示 或
  • 使用 &&,and表示 与
  • 使用not,!表示 非

AopTest类中增加切点:controller包下任何类中public方法

java

代码解读

复制代码

  // controller包下任意类中public方法,都是切点
  @Pointcut("execution(public com.learn.more.controller.*.*(..))")
  public void pointcut() {
  }

3.1.4 定义通知

spring中有5类通知,对应5个用于方法上的注解:方法本身就是切面动作,注解则声明了执行时机

  • @Before:在切点方法之前执行。
  • @After:在切点方法之后执行
  • @AfterReturning:切点方法返回后执行
  • @AfterThrowing:切点方法抛异常执行
  • @Around:属于环绕增强,能控制在切点执行前和执行后,执行自定义逻辑

AopTest类中增加以下通知。

java

代码解读

复制代码

  @Before("pointcut()")
  public void beforeAdvice() {
    log.info("before advice...");
  }

  @After("pointcut()")
  public void afterAdvice() {
    log.info("after advice...");
  }

  @Around("pointcut()")
  public Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    log.info("around before");
    try {
      Object result = proceedingJoinPoint.proceed();
      log.info("around result: {}", result);
      return result;
    } catch (Throwable t) {
      log.error("around error: ", t);
      throw t;
    } finally {
      log.info("around after");
    }
  }

3.1.5 测试

使用postman访问GET http://localhost:8010/user/queryAll 运行结果如下。


转载来源:https://juejin.cn/post/7375072185209438220

相关文章
|
3月前
|
Java
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
|
28天前
|
存储 缓存 Java
Spring高手之路23——AOP触发机制与代理逻辑的执行
本篇文章深入解析了Spring AOP代理的触发机制和执行流程,从源码角度详细讲解了Bean如何被AOP代理,包括代理对象的创建、配置与执行逻辑,帮助读者全面掌握Spring AOP的核心技术。
34 3
Spring高手之路23——AOP触发机制与代理逻辑的执行
|
13天前
|
Java Spring
[Spring]aop的配置与使用
本文介绍了AOP(面向切面编程)的基本概念和核心思想。AOP是Spring框架的核心功能之一,通过动态代理在不修改原代码的情况下注入新功能。文章详细解释了连接点、切入点、通知、切面等关键概念,并列举了前置通知、后置通知、最终通知、异常通知和环绕通知五种通知类型。
26 1
|
9天前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
19 0
|
2月前
|
设计模式 Java 测试技术
spring复习04,静态代理动态代理,AOP
这篇文章讲解了Java代理模式的相关知识,包括静态代理和动态代理(JDK动态代理和CGLIB),以及AOP(面向切面编程)的概念和在Spring框架中的应用。文章还提供了详细的示例代码,演示了如何使用Spring AOP进行方法增强和代理对象的创建。
spring复习04,静态代理动态代理,AOP
|
1月前
|
Java 编译器 Spring
Spring AOP 和 AspectJ 的区别
Spring AOP和AspectJ AOP都是面向切面编程(AOP)的实现,但它们在实现方式、灵活性、依赖性、性能和使用场景等方面存在显著区别。‌
65 2
|
1月前
|
Java Spring 容器
Spring IOC、AOP与事务管理底层原理及源码解析
【10月更文挑战第1天】Spring框架以其强大的控制反转(IOC)和面向切面编程(AOP)功能,成为Java企业级开发中的首选框架。本文将深入探讨Spring IOC和AOP的底层原理,并通过源码解析来揭示其实现机制。同时,我们还将探讨Spring事务管理的核心原理,并给出相应的源码示例。
126 9
|
1月前
|
XML Java 数据格式
Spring的IOC和AOP
Spring的IOC和AOP
45 0
|
2月前
|
Java 数据库连接 数据库
Spring基础3——AOP,事务管理
AOP简介、入门案例、工作流程、切入点表达式、环绕通知、通知获取参数或返回值或异常、事务管理
Spring基础3——AOP,事务管理
|
3月前
|
XML Java 数据格式
Spring5入门到实战------11、使用XML方式实现AOP切面编程。具体代码+讲解
这篇文章是Spring5框架的AOP切面编程教程,通过XML配置方式,详细讲解了如何创建被增强类和增强类,如何在Spring配置文件中定义切入点和切面,以及如何将增强逻辑应用到具体方法上。文章通过具体的代码示例和测试结果,展示了使用XML配置实现AOP的过程,并强调了虽然注解开发更为便捷,但掌握XML配置也是非常重要的。
Spring5入门到实战------11、使用XML方式实现AOP切面编程。具体代码+讲解