Spring Boot – AOP Around Advice
顾名思义,面向方面的编程(AOP)在编程中使用方面。它可以定义为将代码分解为不同的模块,也称为模块化,其中方面是模块化的关键单元。方面支持横切关注点的实现,例如事务、日志记录,这些不是业务逻辑的核心,而不会使代码核心与其功能杂乱无章。它通过添加作为现有代码建议的附加行为来实现。例如,安全是一个横切关注点,在应用程序的许多方法中可以应用安全规则,因此在每个方法中重复代码,在公共类中定义功能,并控制在整个应用程序中应用该功能。在本文中,我们将介绍一个围绕建议的工作示例。
Tip: Aspect-Oriented Programming and AOP in Spring Framework is required as a pre-requisite before proceeding further.
围绕建议是所有建议中最强的建议,因为它“围绕”匹配的方法执行,即在建议方法之前和之后运行。它可以通过返回自己的返回值或抛出异常来选择是继续到连接点还是绕过连接点。这种类型的建议用于我们需要频繁访问方法或数据库,如缓存或以线程安全的方式在方法执行之前和之后共享状态(例如,启动和停止计时器)。
用@Around注解表示。建议方法需要特殊参数。第一个参数必须是 ProceedingJoinPoint 类型。我们对此调用proceed()方法来执行关节点方法。我们可以传递一个 Object 数组来执行方法,以在方法执行时用作方法执行的参数。
在 Spring Boot 应用程序中围绕 Advice 实现 AOP 的步骤
第 1 步:打开 Spring Initializr
第 2 步:提供组名称:com.around
第 3 步:提供工件 ID :aop-around-example
第 4 步:添加Spring Web依赖项。
第五步:点击生成按钮。一个 zip 文件将被下载到系统中。提取它。
步骤 6:使用以下步骤在 IDE 中导入文件夹:
File ->
Import ->
Existing Maven Projects ->
Next ->
Browse ->
Look for the folder aop-around-advice-example
-> Finish
导入项目时,它将安装依赖项。完成后,请按照以下步骤操作。
第七步:在 pom.xml 中添加 spring AOP 的依赖
一、pom.xml
XML
4.0.0
com.around_advice
aop-around-advice-example
0.0.1-SNAPSHOT
jar
aop-around-advice-example
Demo project for Spring Boot AOP Around Advice
org.springframework.boot
spring-boot-starter-parent
2.2.2.RELEASE
UTF-8
UTF-8
1.8
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-aop
org.springframework.boot
spring-boot-maven-plugin
Java
// Java Program to Illustrate Student class
package com.around_advice.model;
// Class
public class Student {
// Class data members
private String firstName;
private String secondName;
// Constructors
public Student() {}
// Getter
public String getFirstName() { return firstName; }
// Setter
public void setFirstName(String firstName)
{
// This keyword refers to current instance itself
this.firstName = firstName;
}
// Getter
public String getSecondName() { return secondName; }
// Setter
public void setSecondName(String secondName)
{
this.secondName = secondName;
}
}
Java
// Java Program to Illustrate StudentService Class
package com.around_advice.service;
// Importing required classes
import com.around_advice.model.Student;
import org.springframework.stereotype.Service;
// Annotation
@Service
// Class
public class StudentService {
// Method
public Student addStudent(String fname, String sname)
{
// Printing name of corresponding student
System.out.println(
"Add student service method called, firstname: "
+ fname + " secondname: " + sname);
Student stud = new Student();
stud.setFirstName(fname);
stud.setSecondName(sname);
// If first name i lesser than 4 words
// display below command
if (fname.length() <= 3)
throw new RuntimeException(
"Length of firstname must be 4 or more");
return stud;
}
}
Java
// Java Program to Illustrate StudentController Class
package com.around_advice.controller;
// Importing required classes
import com.around_advice.model.Student;
import com.around_advice.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
// Annotation
@RestController
// Class
public class StudentController {
@Autowired private StudentService studentService;
@GetMapping(value = "/add")
public Student addStudent(
@RequestParam("firstName") String firstName,
@RequestParam("secondName") String secondName)
{
return studentService.addStudent(firstName,
secondName);
}
}
Java
package com.around_advice.aspect;
// Importing required classes
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
// Annotation
@Aspect
@Component
// Class
public class StudentServiceAspect {
// pointcut expression specifying execution
// of any method in class of any return type
// with 0 or more number of arguments
@Pointcut(
"execution(* com.around_advice.service.StudentService.*(..)) ")
// pointcut signature
private void
anyStudentService()
{
}
@Around("anyStudentService() && args(fname, sname)")
// Method
public Object
beforeAdvice(ProceedingJoinPoint proceedingJoinPoint,
String fname, String sname)
throws Throwable
{
// Print statements
System.out.println(
"Around method:"
+ proceedingJoinPoint.getSignature());
System.out.println(
"Before calling joint point service method");
Object stud = proceedingJoinPoint.proceed();
// Print statement
System.out.println(
"After calling joint point service method ");
return stud;
}
}
保存更改,它将下载 jar。完成后,继续下一步。
Note: If the jars are not added properly, you may get some errors.
第 8 步:创建一个名为 com.around_advice.model 的包。并向其添加一个学生模型类。
B. 学生班
Java
// Java Program to Illustrate Student class
package com.around_advice.model;
// Class
public class Student {
// Class data members
private String firstName;
private String secondName;
// Constructors
public Student() {}
// Getter
public String getFirstName() { return firstName; }
// Setter
public void setFirstName(String firstName)
{
// This keyword refers to current instance itself
this.firstName = firstName;
}
// Getter
public String getSecondName() { return secondName; }
// Setter
public void setSecondName(String secondName)
{
this.secondName = secondName;
}
}
第 9 步:创建一个名为 com.around_advice.service 的包,并向其中添加一个 Student Service 类。添加一个方法来添加具有给定名称参数的学生。
C. StudentService 类
Java
// Java Program to Illustrate StudentService Class
package com.around_advice.service;
// Importing required classes
import com.around_advice.model.Student;
import org.springframework.stereotype.Service;
// Annotation
@Service
// Class
public class StudentService {
// Method
public Student addStudent(String fname, String sname)
{
// Printing name of corresponding student
System.out.println(
"Add student service method called, firstname: "
+ fname + " secondname: " + sname);
Student stud = new Student();
stud.setFirstName(fname);
stud.setSecondName(sname);
// If first name i lesser than 4 words
// display below command
if (fname.length() <= 3)
throw new RuntimeException(
"Length of firstname must be 4 or more");
return stud;
}
}
第 10 步:创建一个名为 com.around_advice.controller 的包。并向其添加一个学生控制器类。添加一个方法来处理 Get 请求并从中调用 Student Service。
D. StudentController 类
Java
// Java Program to Illustrate StudentController Class
package com.around_advice.controller;
// Importing required classes
import com.around_advice.model.Student;
import com.around_advice.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
// Annotation
@RestController
// Class
public class StudentController {
@Autowired private StudentService studentService;
@GetMapping(value = "/add")
public Student addStudent(
@RequestParam("firstName") String firstName,
@RequestParam("secondName") String secondName)
{
return studentService.addStudent(firstName,
secondName);
}
}
第 11 步:创建一个名为 com.around_advice.aspect 的包,并向其中添加一个 Student Service Aspect 类。在这里,我们将添加我们的 Advice 方法和 PointCut 表达式。
E. StudentServiceAspect 类
Java
package com.around_advice.aspect;
// Importing required classes
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
// Annotation
@Aspect
@Component
// Class
public class StudentServiceAspect {
// pointcut expression specifying execution
// of any method in class of any return type
// with 0 or more number of arguments
@Pointcut(
"execution(* com.around_advice.service.StudentService.*(..)) ")
// pointcut signature
private void
anyStudentService()
{
}
@Around("anyStudentService() && args(fname, sname)")
// Method
public Object
beforeAdvice(ProceedingJoinPoint proceedingJoinPoint,
String fname, String sname)
throws Throwable
{
// Print statements
System.out.println(
"Around method:"
+ proceedingJoinPoint.getSignature());
System.out.println(
"Before calling joint point service method");
Object stud = proceedingJoinPoint.proceed();
// Print statement
System.out.println(
"After calling joint point service method ");
return stud;
}
}
第 12 步:我们完成了代码结构。现在要运行应用程序,将应用程序启动为“作为启动应用程序运行”。打开浏览器并点击以下 URL 进行获取请求调用:http://localhost:{portNumber}/add?firstName={fname}&secondName={sname}
对于演示,我们使用 fname 为 Harry 和 sname 为 Potter 来访问 URL。在这种情况下,该方法将正常执行。
当我们点击 fname 为 Tom 的 URL 时,服务方法将抛出异常。不会执行周围的建议。
从输出中可以看出,Around 通知通过proceed() 调用连接点,我们可以在此之前和之后添加要执行的逻辑。