一、前言
Spring AOP(面向切面编程)是一种强大的范式,用于模块化应用程序中的横切关注点。切入点(Pointcut)是一组一个或多个连接点(Join Point)的集合,在这些连接点上应该应用通知(Advice)。连接点是程序执行过程中的一个点,比如方法执行、对象实例化或字段访问。切入点定义了通知执行的时机和位置。
二、基本概念
切面(Aspect):切面是跨越多个类和对象关注点的模块化,如日志记录、事务管理等。在Spring AOP中,切面可以使用基于注解或XML的方式定义。
连接点(Joinpoint):程序执行过程中的一个点,如方法的执行或异常的处理。在Spring AOP中,连接点通常指的是方法的执行。
切入点(Pointcut):用于定义哪些连接点(即哪些方法)会被切面增强。切入点表达式决定了哪些类的哪些方法会被拦截。
通知(Advice):在切面的某个特定连接点上执行的动作。Spring AOP支持五种类型的通知:前置通知、后置通知(返回后)、环绕通知、异常通知和最终通知。
代理(Proxy):Spring AOP通过代理机制实现切面功能。根据目标对象是否实现接口,Spring AOP会选择使用JDK动态代理或CGLIB代理。
三、高级用法
1. 复杂的切入点表达式
Spring AOP使用AspectJ切入点表达式语言来定义切入点。除了基本的执行表达式(execution)外,还支持within、this、target、args、@target、@within、@annotation等多种类型的表达式,用于更精确地匹配连接点。
execution基本用法
execution(* com.pack.UserService.*(..))匹配指定包和类中的所有方法
execution(*UserService.*(..))匹配同一包和指定类中的所有方法
execution(public *UserService.*(..))匹配UserService中的所有公共方法
execution(public UserUserService.*(..))匹配UserService中所有返回类型为 User 对象的公共方法
execution(public UserUserService.*(User, ..))匹配UserService中所有返回类型为 User 且第一个参数为 User 的公共方法
execution(public UserUserService.*(User, Integer)) 匹配UserService中所有返回类型为 User 且带有指定参数的公共方法
高级用法within()
可以指定某一类型或包中的连接点
within(com.pack.service.*) 该表达式匹配"com.pack.service"包中的所有方法。
within(com.pack..*)匹配包"com.pack"中所有类的所有方法,以及所有子包中的类
within(com.pack.UserService)匹配指定包中指定类的所有方法
within(UserService)匹配当前包中指定类的所有方法
within(IUserService+)匹配指定接口所有实现中的所有方法
bean表达式
匹配所有符合指定模式的类中的所有方法
bean(*Service)匹配 bean 中名称以 "Service"结尾的所有方法
bean(userService)匹配指定 Bean 中名称为 "userService "的所有方法
bean(com.pack.service.*)匹配特定包中所有bean的所有方法
bean(@PackAnnotation *)将所有 Bean 中的所有方法与特定注解相匹配
2. @Aspect顺序
当存在多个切面时,这些切面可能会同时对同一个方法进行增强操作。为了控制这些切面的执行顺序,可以使用@Order注解来指定它们的优先级。数值越小的切面具有更高的优先级,即会先执行。
代码示例
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
@Aspect
@Order(value = 1) // 指定FirstAspect的优先级为1
public class FirstAspect {
@Before("execution(* com.example.service.*.*(..))")
public void beforeAdvice() {
System.out.println("First aspect executed before method execution");
}
}
@Aspect
@Order(value = 2) // 指定SecondAspect的优先级为2,因此会在FirstAspect之后执行
public class SecondAspect {
@Before("execution(* com.example.service.*.*(..))")
public void beforeAdvice() {
System.out.println("Second aspect executed before method execution");
}
}
除了使用@Order注解外,还可以通过实现Ordered接口并覆盖getOrder()方法来指定顺序。但在Spring 4.0及更高版本中,推荐使用@Order注解,因为它更加简洁易用。
代码示例
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.Ordered;
@Aspect
public class OrderedAspect implements Ordered {
@Override
public int getOrder() {
// 返回的数值越小,优先级越高,即该切面会先执行
return 1;
}
@Before("execution(* com.example.service.*.*(..))")
public void beforeAdvice() {
System.out.println("Ordered aspect executed before method execution");
}
}
// 另一个切面,也实现了Ordered接口
@Aspect
public class AnotherOrderedAspect implements Ordered {
@Override
public int getOrder() {
// 返回的数值比OrderedAspect大,因此该切面会在OrderedAspect之后执行
return 2;
}
@Before("execution(* com.example.service.*.*(..))")
public void anotherBeforeAdvice() {
System.out.println("Another ordered aspect executed before method execution");
}
}
3. 动态代理的选择
当目标对象没有实现接口时,Spring AOP默认使用CGLIB代理。但也可以通过配置强制使用CGLIB代理,即使目标对象实现了接口。
配置方式包括在XML配置文件中使用<aop:config proxy-target-class="true">或在<aop:aspectj-autoproxy>标签中设置proxy-target-class="true"。
4. 顾问(Advisor)
顾问是切面的另一种实现方式,它将通知与切入点表达式封装在一起,提供了更灵活的切面配置方式。Spring提供了多种顾问实现,如NameMatchMethodPointcutAdvisor可以根据方法名匹配切入点。
代码示例
@Bean
public Advisor nameMatchMethodPointcutAdvisor() {
NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
pointcut.setMappedNames("mySpecialMethod");
MethodInterceptor interceptor = new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Before invoking " + invocation.getMethod().getName());
Object result = invocation.proceed();
System.out.println("After invoking " + invocation.getMethod().getName());
return result;
}
};
return new DefaultPointcutAdvisor(pointcut, interceptor);
}
四、总结
Spring AOP的高级用法涉及复杂的切入点表达式、环绕通知、动态代理的选择、顾问的使用以及声明式事务管理等方面。掌握这些高级用法可以帮助开发者更加灵活地使用Spring AOP,实现更加复杂和高效的切面编程。同时,也需要注意性能优化问题,以确保系统的稳定性和高效性。
标签:匹配,Spring,用法,切面,AOP,execution,public From: https://blog.csdn.net/A79800/article/details/142594838