Spring:Spring AOP的高级用法

一、前言

  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,实现更加复杂和高效的切面编程。同时,也需要注意性能优化问题,以确保系统的稳定性和高效性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值