赞
踩
使用AOP可以将那些与核心业务逻辑无关但又分散在各处的横切关注点(如日志记录、性能监控、事务管理等)抽离出来,通过切面的方式进行统一管理和维护,从而提高了代码的模块化程度、可维护性和可扩展性。
关系图:
Spring AOP相对于传统AOP来说更加轻量级和易用,适合于大部分应用场景下的AOP需求。传统AOP则提供了更丰富的功能和更灵活的配置选项,适用于对AOP功能有更高要求的特定场景。
实现与扩展方面的区别和优势:
接口 Pointcut 表示一个切点,可以确定哪些类和方法应该被包含在一个切面中。通过提供类过滤器和方法匹配器,允许开发者定义更加精确的切点条件。
本文仅仅分析用于确定给定方法是否匹配切点条件的matches方法,对于实现类的其它方法,读者感兴趣可自行解读,亦可以期待后续的博文。
第一个 matches
方法位于 ShadowMatch
对象上,用于判断连接点是否匹配切点条件。这个方法是由 ShadowMatch
类提供的,用于执行切点表达式与目标方法的匹配逻辑。
第二个 matches
方法位于 JoinPointMatch
对象上,用于判断连接点的匹配状态。这个方法是由 JoinPointMatch
类提供的,用于判断连接点是否成功匹配了切点表达式。
检查给定的方法名是否与列表中的任何一个方法名匹配。
用于判断一个字符串是否符合给定的模式,源码结合切面表达式看易于理解。
/**
* execution(): 这是最常用的切入点函数,在方法执行时触发切入点
* 切入点函数参数: 包括方法的访问修饰符、返回类型、类名、方法名和参数列表等
* 通配符: 例如*用于匹配任意字符,..用于匹配任意数量的参数等
* 逻辑运算符: 例如&&表示与,||表示或,!表示非
*/
@Pointcut("execution(* com.example.service.*.*(..))")
private void serviceMethods() {}
Advice
接口有多个子接口,如MethodBeforeAdvice
、AfterReturningAdvice
、ThrowsAdvice
等。本文解读前置通知,其它通知读者感兴趣可以自行去了解。
通知类型可以分为以下几种:
org.springframework.aop.MethodBeforeAdvice
接口的通知称为前置通知。org.springframework.aop.AfterReturningAdvice
接口的通知称为后置通知。org.aopalliance.intercept.MethodInterceptor
接口的通知称为环绕通知。org.springframework.aop.ThrowsAdvice
接口的通知称为抛出异常通知。org.springframework.aop.IntroductionInterceptor
接口的通知称为引介通知。用于在目标方法执行之前执行某些操作。
主要作用是在目标方法执行前执行一些额外的操作。
Spring AOP是 Spring 框架的一个重要特性,允许以声明性方式来定义横切关注点,如日志记录、性能监控、事务管理等,而无需修改业务逻辑代码。
Spring AOP 的使用XML形式的Demo,包括配置方式和用法:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.9</version> <!-- 版本号可以根据实际情况调整 -->
</dependency>
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
/**
* @Aspect 注解表示这是一个切面类
* @Before 注解表示在目标方法执行之前执行通知
* 切入点表达式指定了切入点为 com.example.service 包中的所有类的所有方法
*/
@Aspect
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logBefore() {
System.out.println("Logging before method execution...");
}
}
<!-- Spring 配置文件中声明切面类为一个 Spring Bean -->
<bean id="loggingAspect" class="com.example.aspect.LoggingAspect"/>
<!-- 在 Spring 配置文件中启用 Spring AOP -->
<aop:aspectj-autoproxy/>
package com.example.service;
public class MyService {
public void doSomething() {
System.out.println("Doing something...");
}
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.example.service.MyService;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
MyService myService = (MyService) context.getBean("myService");
myService.doSomething();
}
}
以订单创建日志记录的Demo:
public interface OrderService {
void createOrder(Order order);
}
@Service
public class OrderServiceImpl implements OrderService {
@Override
public void createOrder(Order order) {
// 创建订单的具体逻辑
System.out.println("订单已创建:" + order);
}
}
public class Order {
private Long id;
private String customerName;
private double amount;
// 省略 getter 和 setter 方法
}
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
/**
* 在LoggingAspect切面类上添加了@Aspect和@Component注解,用于告诉Spring这是一个切面类,并将其纳入Spring容器管理
*/
@Aspect
@Component
public class LoggingAspect {
/**
* 使用了@Before注解来定义了一个前置通知
* 执行OrderService接口的createOrder方法之前被触发
* 切入点表达式指定切入点为OrderService接口的createOrder方法
*/
@Before("execution(* com.example.service.OrderService.createOrder(..)) && args(order)")
public void logBefore(Order order) {
System.out.println("订单已创建,订单ID:" + order.getId() + ",客户姓名:" + order.getCustomerName());
System.out.println("记录订单创建日志...");
}
}
/**
* 使用了@Configuration、@ComponentScan和@EnableAspectJAutoProxy注解来启用Spring AOP和组件扫描
*/
@Configuration
@ComponentScan(basePackages = "com.example")
@EnableAspectJAutoProxy
public class AppConfig {
}
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
OrderService orderService = context.getBean(OrderService.class);
Order order = new Order();
order.setId(1L);
order.setCustomerName("Alice");
order.setAmount(100.0);
orderService.createOrder(order);
}
}
// 输出结果
订单已创建,订单ID:1,客户姓名:Alice
记录订单创建日志...
订单已创建:Order{id=1, customerName='Alice', amount=100.0}
古人学问无遗力,少壮工夫老始成
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。