Spring AOP编程
大约 4 分钟
Spring AOP编程
什么是AOP
面向切面编程(Aspect-Oriented Programming,AOP)是Spring框架的另一个核心特性。AOP通过预编译方式和运行期动态代理实现程序功能的统一维护,是OOP(面向对象编程)的有益补充。
AOP的核心概念
- 切面(Aspect):横切关注点的模块化,包含通知和切入点
- 连接点(Join Point):程序执行过程中的某个点,如方法调用或异常处理
- 切入点(Pointcut):匹配连接点的谓词,决定哪些连接点会被通知
- 通知(Advice):在特定连接点执行的代码
- 目标对象(Target Object):被一个或多个切面通知的对象
- 织入(Weaving):将切面应用到目标对象以创建新代理对象的过程
- 引入(Introduction):为类添加新方法或属性
- 代理(Proxy):向目标对象应用通知后创建的对象
AOP通知类型
Spring AOP支持五种类型的通知:
1. 前置通知(Before Advice)
在目标方法执行之前执行的通知:
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void beforeAdvice(JoinPoint joinPoint) {
System.out.println("方法执行前: " + joinPoint.getSignature().getName());
}
}2. 后置通知(After Advice)
在目标方法执行之后执行的通知(无论是否抛出异常):
@Aspect
@Component
public class LoggingAspect {
@After("execution(* com.example.service.*.*(..))")
public void afterAdvice(JoinPoint joinPoint) {
System.out.println("方法执行后: " + joinPoint.getSignature().getName());
}
}3. 返回通知(After Returning Advice)
在目标方法成功执行后执行的通知:
@Aspect
@Component
public class LoggingAspect {
@AfterReturning(pointcut = "execution(* com.example.service.*.*(..))",
returning = "result")
public void afterReturningAdvice(JoinPoint joinPoint, Object result) {
System.out.println("方法返回值: " + result);
}
}4. 异常通知(After Throwing Advice)
在目标方法抛出异常后执行的通知:
@Aspect
@Component
public class LoggingAspect {
@AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))",
throwing = "ex")
public void afterThrowingAdvice(JoinPoint joinPoint, Exception ex) {
System.out.println("方法抛出异常: " + ex.getMessage());
}
}5. 环绕通知(Around Advice)
围绕目标方法执行的通知,可以控制方法是否执行:
@Aspect
@Component
public class LoggingAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
System.out.println("方法开始执行: " + joinPoint.getSignature().getName());
try {
Object result = joinPoint.proceed();
return result;
} finally {
long endTime = System.currentTimeMillis();
System.out.println("方法执行结束,耗时: " + (endTime - startTime) + "ms");
}
}
}切入点表达式
切入点表达式用于定义哪些连接点会被通知:
常用切入点表达式
- execution:匹配方法执行连接点
- within:匹配指定类型内的方法执行
- this:匹配实现了指定接口的目标对象方法
- target:匹配指定类型的实例方法
- args:匹配参数类型匹配的方法
execution表达式详解
// 匹配任何返回值,com.example.service包下任何类的任何方法
@Pointcut("execution(* com.example.service.*.*(..))")
// 匹配返回UserService的任何方法
@Pointcut("execution(com.example.service.UserService *(..))")
// 匹配UserService类中的getUser方法
@Pointcut("execution(* com.example.service.UserService.getUser(..))")
// 匹配以save开头的方法
@Pointcut("execution(* save*(..))")AOP配置方式
基于注解的配置
@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackages = "com.example")
public class AopConfig {
// 配置类
}
@Aspect
@Component
public class TransactionAspect {
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceLayer() {}
@Before("serviceLayer()")
public void beginTransaction() {
System.out.println("开启事务");
}
@After("serviceLayer()")
public void commitTransaction() {
System.out.println("提交事务");
}
}基于XML的配置
<aop:config>
<aop:aspect id="transactionAspect" ref="transactionAspectBean">
<aop:pointcut id="serviceLayer"
expression="execution(* com.example.service.*.*(..))"/>
<aop:before pointcut-ref="serviceLayer" method="beginTransaction"/>
<aop:after pointcut-ref="serviceLayer" method="commitTransaction"/>
</aop:aspect>
</aop:config>AOP实际应用
事务管理
@Aspect
@Component
public class TransactionAspect {
@Around("@annotation(org.springframework.transaction.annotation.Transactional)")
public Object manageTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
// 开启事务
System.out.println("开启事务");
try {
Object result = joinPoint.proceed();
// 提交事务
System.out.println("提交事务");
return result;
} catch (Exception e) {
// 回滚事务
System.out.println("回滚事务");
throw e;
}
}
}性能监控
@Aspect
@Component
public class PerformanceMonitorAspect {
private static final Logger logger = LoggerFactory.getLogger(PerformanceMonitorAspect.class);
@Around("execution(* com.example.service.*.*(..))")
public Object monitorPerformance(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
try {
return joinPoint.proceed();
} finally {
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
logger.info("方法 {} 执行耗时: {} ms",
joinPoint.getSignature().toShortString(), duration);
}
}
}权限检查
@Aspect
@Component
public class SecurityAspect {
@Before("@annotation(com.example.annotation.RequirePermission)")
public void checkPermission(JoinPoint joinPoint) {
// 获取方法上的注解
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
RequirePermission annotation = signature.getMethod()
.getAnnotation(RequirePermission.class);
String requiredPermission = annotation.value();
// 检查当前用户是否具有所需权限
if (!hasPermission(requiredPermission)) {
throw new SecurityException("权限不足");
}
}
private boolean hasPermission(String permission) {
// 实际权限检查逻辑
return true;
}
}AOP代理机制
Spring AOP使用两种代理机制:
JDK动态代理
当目标对象实现了接口时,Spring使用JDK动态代理:
public interface UserService {
void saveUser(User user);
}
public class UserServiceImpl implements UserService {
@Override
public void saveUser(User user) {
// 业务逻辑
}
}CGLIB代理
当目标对象没有实现接口时,Spring使用CGLIB代理:
public class UserService {
public void saveUser(User user) {
// 业务逻辑
}
}代理配置
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true) // 强制使用CGLIB代理
public class AopConfig {
// 配置
}通过以上内容,我们可以全面了解Spring AOP的原理和应用。AOP是Spring框架的重要组成部分,通过横切关注点的分离,使得代码更加模块化和易于维护。
