让我用一个餐厅服务的例子来解释Spring AOP:
- 基本概念展示:
// 核心业务逻辑(相当于餐厅的点菜服务)
public interface OrderService {
void createOrder(String dish);
}
// 实现类
@Service
public class OrderServiceImpl implements OrderService {
@Override
public void createOrder(String dish) {
System.out.println("制作菜品: " + dish);
}
}
// 切面(相当于服务流程的统一处理)
@Aspect
@Component
public class ServiceAspect {
// 定义切点(相当于确定在哪些服务环节进行处理)
@Pointcut("execution(* com.example.service.*.*(..))")
public void servicePointcut() {}
// 前置通知(相当于服务前的准备工作)
@Before("servicePointcut()")
public void beforeService(JoinPoint joinPoint) {
System.out.println("服务准备: 清洁餐具");
}
// 后置通知(相当于服务后的收尾工作)
@After("servicePointcut()")
public void afterService() {
System.out.println("服务结束: 清理餐桌");
}
// 环绕通知(相当于完整的服务流程控制)
@Around("servicePointcut()")
public Object aroundService(ProceedingJoinPoint joinPoint)
throws Throwable {
// 开始计时
long start = System.currentTimeMillis();
// 执行原有服务
Object result = joinPoint.proceed();
// 记录服务时间
long time = System.currentTimeMillis() - start;
System.out.println("服务用时: " + time + "ms");
return result;
}
}
- 实际应用示例:
// 日志切面
@Aspect
@Component
public class LoggingAspect {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Around("@annotation(LogExecutionTime)")
public Object logExecutionTime(ProceedingJoinPoint joinPoint)
throws Throwable {
long start = System.currentTimeMillis();
Object proceed = joinPoint.proceed();
long executionTime = System.currentTimeMillis() - start;
logger.info(joinPoint.getSignature() + " executed in " +
executionTime + "ms");
return proceed;
}
}
// 自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecutionTime {
}
// 使用切面
@Service
public class UserService {
@LogExecutionTime
public User findById(Long id) {
// 业务逻辑
return userRepository.findById(id);
}
}
- 事务管理示例:
@Aspect
@Component
public class TransactionAspect {
@Around("@annotation(Transactional)")
public Object handleTransaction(ProceedingJoinPoint joinPoint)
throws Throwable {
TransactionStatus status = null;
try {
// 开启事务
status = beginTransaction();
// 执行业务逻辑
Object result = joinPoint.proceed();
// 提交事务
commitTransaction(status);
return result;
} catch (Exception e) {
// 回滚事务
if (status != null) {
rollbackTransaction(status);
}
throw e;
}
}
}
// 使用事务切面
@Service
public class OrderService {
@Transactional
public void createOrder(Order order) {
// 创建订单的业务逻辑
}
}
- 缓存切面示例:
@Aspect
@Component
public class CacheAspect {
private Map<String, Object> cache = new ConcurrentHashMap<>();
@Around("@annotation(Cacheable)")
public Object handleCache(ProceedingJoinPoint joinPoint)
throws Throwable {
// 生成缓存key
String key = generateKey(joinPoint);
// 检查缓存
if (cache.containsKey(key)) {
return cache.get(key);
}
// 执行方法
Object result = joinPoint.proceed();
// 存入缓存
cache.put(key, result);
return result;
}
}
// 使用缓存切面
@Service
public class ProductService {
@Cacheable
public Product getProductById(Long id) {
// 获取商品信息的业务逻辑
}
}
- 权限检查切面:
@Aspect
@Component
public class SecurityAspect {
@Before("@annotation(RequiresPermission)")
public void checkPermission(JoinPoint joinPoint) {
// 获取当前用户
User user = getCurrentUser();
// 获取所需权限
RequiresPermission annotation = ((MethodSignature) joinPoint
.getSignature())
.getMethod()
.getAnnotation(RequiresPermission.class);
// 检查权限
if (!hasPermission(user, annotation.value())) {
throw new AccessDeniedException("权限不足");
}
}
}
// 使用权限检查
@Service
public class AdminService {
@RequiresPermission("ADMIN")
public void performAdminOperation() {
// 管理员操作
}
}
AOP的主要应用场景:
- 日志记录
- 性能监控
- 事务管理
- 安全检查
- 缓存管理
- 错误处理
它就像餐厅服务中的标准流程:
- 核心业务(点菜、做菜)是主要服务
- 切面(清洁、记录、计时)是辅助流程
- 两者结合提供完整的服务体验
AOP的优势:
- 代码重用
- 关注点分离
- 维护性提高
- 代码简洁