详解Java Spring AOP
什么是AOP?
AOP代表面向切面编程。它是一种编程范例,它允许开发人员将行为分割成各个部分或单独的功能,在这些功能之间划清界限。AOP可以在程序的多个模块中实现可重用性,并使它更加容易测试和维护。
为什么要使用AOP?
AOP 可以很好地解决几个横跨多个对象和层的问题:
- 记录日志、时间性能、监控对象的方法
- 对象在不同时间可能处于不同的状态,如读写、注销等
- 在对象被创建和垃圾回收时采取措施
- 是否有用户访问安全性检查的权限
尽管我们可以使用传统的OOP技术来解决这些问题,但使用AOP可以更容易地实现这一点,因为它允许我们以功能方式划分代码。许多框架和工具可以使用AOP作为自己的底层,这使得AOP易于集成并且易于使用。
Spring AOP
Spring AOP是Spring Framework中的一个模块,用于支持基于切面的编程。它使用JDK动态代理或CGLIB实现AOP。
Spring AOP提供了三种类型的通知:
- 前置通知:在方法执行之前执行的代码
- 后置通知:在方法执行之后执行的代码,无论其结果如何
- 环绕通知:在方法执行之前和之后执行的代码
对于 Spring AOP 中的所有通知类型,代码示例如下所示:
@Before("execution(* com.example.demo.service.*.*(..))")
public void beforeAdvice(JoinPoint joinPoint) {
System.out.println("Before method:" + joinPoint.getSignature());
}
@After("execution(* com.example.demo.service.*.*(..))")
public void afterAdvice(JoinPoint joinPoint) {
System.out.println("After method:" + joinPoint.getSignature());
}
@Around("execution(* com.example.demo.service.*.*(..))")
public void aroundAdvice(JoinPoint joinPoint) {
System.out.println("Around method start :" + joinPoint.getSignature());
try {
((ProceedingJoinPoint) joinPoint).proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("Around method end :" + joinPoint.getSignature());
}
示例一
假设我们有一个简单的UserService,它有一个getUserName(String userId)方法,返回给定UserID的用户名。我们要对该方法进行AOP处理以记录每个用户的访问。
Step 1: 创建一个注解 @UserAccessLog
@Retention(RetentionPolicy.RUNTIME)
public @interface UserAccessLog {
}
Step 2: 在UserService中添加上述注解,并创建切面类UserAccessLoggingAspect:
@Service
public class UserService {
@UserAccessLog
public String getUserName(String userId) {
// logic to get user name
}
}
@Component
public class UserAccessLoggingAspect {
@Before("@annotation(userAccessLog)")
public void logBeforeUserAccessWithId(UserAccessLog userAccessLog) {
System.out.println("User with ID accessed app.");
}
}
Step 3: 我们运行这个示例,让它返回用户名时,将在控制台上打印一条消息:
userService.getUserName("user123");
输出:
User with ID accessed app.
示例二
假设我们有一个简单的CalculatorService,它只是执行乘法操作并在控制台上log它。我们要对该方法进行AOP处理以记录每次操作的乘积。
Step 1: 创建一个注解 @MultiplicationLogging
@Retention(RetentionPolicy.RUNTIME)
public @interface MultiplicationLogging {
}
Step 2: 在CalculatorService中添加上述注解,并创建切面类MultiplicationLoggingAspect:
@Service
public class CalculatorService {
@MultiplicationLogging
public int multiply(int a, int b) {
return a * b;
}
}
@Component
public class MultiplicationLoggingAspect {
@Before("@annotation(multiplicationLogging)")
public void logBeforeMultiplication(MultiplicationLogging multiplicationLogging, JoinPoint joinPoint) {
int firstParam = (int) joinPoint.getArgs()[0];
int secondParam = (int) joinPoint.getArgs()[1];
System.out.println("Multiplying " + firstParam + " and " + secondParam);
}
@AfterReturning(value = "@annotation(multiplicationLogging)", returning = "result")
public void logAfterMultiplication(MultiplicationLogging multiplicationLogging, JoinPoint joinPoint, Object result) {
System.out.println("Result of multiplication: " + result);
}
}
Step 3: 我们运行这个示例,并且当它打印乘积时控制台上将打印两条消息:
calculatorService.multiply(5, 10);
Output:
Multiplying 5 and 10
Result of multiplication: 50
总结
使用Spring AOP,我们可以捕获不同类型的通知和建立通用代码,而不是维护多个依赖于核心业务逻辑的支持代码。通过编写通用代码,使我们可以降低应用程序的相关复杂度,通过减轻其负担而使程序具有更高的内聚性和复用性。这也使得代码更容易阅读,更容易维护。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解Java Spring AOP - Python技术站