多个类下所有方法AOP

微服务下有两个类,需要做异常捕获再抛出,笔者立马想到了AOP
非微服务,只能使用代理

@Slf4j
@Aspect
@Component
public class SdkAspect {

    @Pointcut("execution(* com.aspire.service.impl.XxxEncryption.*(..))")
    public void enPointcut() {
    }

    @Pointcut("execution(* com.aspire.service.impl.XxxSignature.*(..))")
    public void signPointcut() {
    }

    @Around("enPointcut() || signPointcut()")
    public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        try {
            // 调用原始方法
            long start = System.currentTimeMillis();
            Object result = joinPoint.proceed();
            long end = System.currentTimeMillis();
            logInfo(joinPoint, start, end);
            return result;
        } catch (Exception e) {
            log.error("调用sdk异常");
            throw e;
        } 

    }

    /**
     * 打印信息
     *
     * @param joinPoint 切点
     * @param start     起始时间
     * @param end       结束时间
     */
    private static void logInfo(ProceedingJoinPoint joinPoint, long start, long end) {
        try {
            // 定位方法
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            long cost = end - start;
            log.info("SDK方法:{} 调用耗时: {} 毫秒", method.getName(), cost);
        } catch (Exception e) {
            log.error("log error {}", e);
        }
    }

}
<think> 我们参考上述引用内容,特别是引用[2]中展示了如何通过配置文件(jboss-aop.xml)将拦截器应用到特定的特定方法上。但是用户的需求是拦截某个下的所有方法,因此我们需要调整切入点表达式(pointcut expression)来匹配下的所有方法。 根据引用[4],切入点表达式的基本语法是: execution(修饰符? 返回路径? 方法名(参数) 异常?) 要拦截某个(例如test.HelloAOP)下的所有方法,我们可以将方法名用通配符*代替,同时参数部分用..表示任意参数。因此,切入点表达式可以写成: execution(* test.HelloAOP.*(..)) 注意:这里我们省略了修饰符(默认为任意修饰符)和异常(通常不写),返回型用*表示任意返回型,路径为test.HelloAOP方法名为*表示所有方法,参数为..表示任意参数。 另外,引用[5]中提到了使用注解的方式定义拦截规则,但用户要求的是拦截某个下所有方法,所以我们可以使用基于execution表达式的配置方式。 下面分别给出两种常见的AOP实现方式(Spring AOP和AspectJ)的示例: 1. Spring AOP(基于代理)的配置方式: 我们可以使用@Aspect注解和@Around等通知注解来定义切面。 2. 使用XML配置(如引用[2]中的jboss-aop.xml)的方式。 但是注意引用[3]中提到的:Spring AOP不能拦截同一个对象内方法的嵌套调用,因为Spring AOP是基于代理的。 由于用户没有指定具体的AOP框架,这里以Spring AOP(使用注解配置)为例: 步骤: a. 定义一个切面,使用@Aspect注解。 b. 定义一个切入点表达式,匹配目标的所有方法。 c. 编写通知方法(如@Around, @Before等)。 示例代码: 假设我们要拦截test.service.UserService下的所有方法。 切面: ```java import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; @Aspect @Component public class LoggingAspect { // 定义切入点:匹配test.service.UserService下的所有方法 @Pointcut("execution(* test.service.UserService.*(..))") public void userServiceMethods() {} // 环绕通知 @Around("userServiceMethods()") public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("方法调用前: " + joinPoint.getSignature().getName()); Object result = joinPoint.proceed(); // 执行目标方法 System.out.println("方法调用后: " + joinPoint.getSignature().getName()); return result; } } ``` 注意:确保Spring配置中启用了AOP支持(例如使用@EnableAspectJAutoProxy注解)。 如果使用XML配置(Spring AOP): ```xml <aop:config> <aop:aspect ref="loggingAspect"> <aop:pointcut id="userServicePointcut" expression="execution(* test.service.UserService.*(..))"/> <aop:around method="logAround" pointcut-ref="userServicePointcut"/> </aop:aspect> </aop:config> <bean id="loggingAspect" class="test.aspect.LoggingAspect"/> ``` 另外,引用[2]中展示了JBoss AOP的配置方式,其原理似,都是通过切入点表达式来匹配。 对于JBoss AOP,配置jboss-aop.xml: ```xml <?xml version="1.0" encoding="UTF-8"?> <aop> <bind pointcut="execution(* test.service.UserService->*(..))"> <interceptor class="test.interceptor.UserServiceInterceptor"/> </bind> </aop> ``` 注意:不同AOP框架在配置上可能有差异,但切入点表达式的写法似。 重要提示:如果使用Spring AOP,由于它是基于代理的,只能拦截public方法(除非使用AspectJ织入方式)。另外,同一个内部方法调用不会被拦截(如引用[3]所述),因为内部调用不会经过代理。 如果用户需要拦截同一个内部的方法调用,可以考虑使用AspectJ(编译时或加载时织入)来代替Spring AOP。 总结: - 使用execution表达式:`execution(* 包名.名.*(..))` 来匹配下所有方法。 - 根据所使用的AOP框架(Spring AOP, AspectJ, JBoss AOP等)编写切面或拦截器。 - 注意代理方式的限制(如Spring AOP只能拦截public方法,且不能拦截内部调用)。 相关问题: 1. 如何编写AOP的切入点表达式来匹配多个? 2. Spring AOP和AspectJ的主要区别是什么? 3. 如何解决Spring AOP中同一个方法调用不被拦截的问题? 4. 除了方法拦截,AOP还可以应用在哪些场景? </think> ### 使用AOP拦截某个下所有方法方法与示例 #### 一、核心实现原理 通过AOP(面向切面编程)拦截指定的所有方法,关键在于**定义匹配该所有方法的切入点表达式(Pointcut Expression)**。核心语法为: $$ \text{execution}(*\ \text{包名.名}.*(..)) $$ 其中: - `*` 表示任意返回型 - `包名.名` 指定目标 - `.*(..)` 匹配该下的所有方法(任意参数) --- #### 二、具体实现示例 ##### 1. 基于注解配置(Spring AOP) ```java import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Aspect @Component public class ClassInterceptorAspect { // 拦截com.example.service.UserService的所有方法 @Before("execution(* com.example.service.UserService.*(..))") public void interceptAllMethods() { System.out.println("拦截到UserService的方法调用"); // 此处添加拦截逻辑(日志、权限校验等) } } ``` ##### 2. 基于XML配置(传统Spring AOP) ```xml <aop:config> <aop:aspect ref="interceptorAspect"> <!-- 拦截com.example.dao.ProductDao的所有方法 --> <aop:pointcut id="productDaoMethods" expression="execution(* com.example.dao.ProductDao.*(..))"/> <aop:before pointcut-ref="productDaoMethods" method="logMethodCall"/> </aop:aspect> </aop:config> <bean id="interceptorAspect" class="com.example.aop.DaoInterceptor"/> ``` ##### 3. 拦截器实现 ```java public class DaoInterceptor { public void logMethodCall(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); System.out.println("拦截到方法: " + methodName); // 可获取参数、返回值等详细信息 } } ``` --- #### 三、关键注意事项 1. **表达式精度控制** - 拦截所有方法:`execution(* com.example.X.*(..))` - 拦截特定修饰符方法:`execution(public * com.example.X.*(..))` - 排除特定方法:`!execution(* toString())` 2. **嵌套调用限制** - Spring AOP基于代理实现,**无法拦截同内部的嵌套方法调用**(如`this.internalMethod()`)[^3] - 解决方案:通过AopContext获取当前代理对象 ```java ((UserService) AopContext.currentProxy()).internalMethod(); ``` 3. **性能优化建议** - 避免在频繁调用的方法上添加复杂拦截逻辑 - 使用`@Around`替代多个独立注解减少代理层级 --- #### 四、典型应用场景 1. **统一日志记录** 自动记录中所有方法的入参、返回值和执行时间 2. **事务管理** 对Service层所有方法添加声明式事务 3. **权限校验** 拦截Controller方法进行登录态验证 4. **性能监控** 统计DAO层所有方法的SQL执行时长 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

*crzep

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值