You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring中Aspect与全局异常处理器无法捕获BotAuthorizeException求助

Spring项目中异常无法捕获问题求助

我在Spring项目里遇到自定义异常BotAuthorizeException既无法被Aspect切面捕获,也无法被全局异常处理器捕获的问题,以下是相关代码和异常日志:

1. 自定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BotExceptionCheck {

}

2. Aspect切面类

@Aspect
@Component
public class BotExceptionCheckAspect {
    SendMessageProducer sendMessageProducer;
    UserService userService;

    public BotExceptionCheckAspect(SendMessageProducer sendMessageProducer, UserService userService) {
        this.sendMessageProducer = sendMessageProducer;
        this.userService = userService;
    }

    @Around("@annotation(BotExceptionCheck)")
    public Object handleException(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result = null;
        try {
            result = joinPoint.proceed();
        } catch (BotAuthorizeException ex) {
            var user = userService.findById(ex.getChatId());
            sendMessageProducer.sendMessage(SendMessage.builder()
                    .chatId(user.getChatId())
                    .text(ex.getMessage())
                    .build());
        }
        return result;
    }
}

3. 抛出异常的方法(已添加注解)

@BotExceptionCheck
public void checkSubscriptionForChannel(ChatMember chatMember) {
    if (chatMember.getStatus().equals("kicked") || chatMember.getStatus().equals("left")) {
        throw new BotAuthorizeException(String.valueOf(chatMember.getUser().getId()), """
                You don't subscribe to the channel
                """);
    }
}

4. 全局异常处理器

@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    SendMessageProducer sendMessageProducer;
    UserService userService;

    public GlobalExceptionHandler(SendMessageProducer sendMessageProducer, UserService userService) {
        this.sendMessageProducer = sendMessageProducer;
        this.userService = userService;
    }

    @ExceptionHandler(BotAuthorizeException.class)
    public void handleBotAuthorizeException(BotAuthorizeException ex){
        var user = userService.findById(ex.getChatId());
        sendMessageProducer.sendMessage(SendMessage.builder()
                .chatId(user.getChatId())
                .text(ex.getMessage())
                .build());
    }
}

异常日志

2023-08-12 10:15:54.070 ERROR 11228 --- [legram Executor] o.t.t.u.DefaultBotSession                : You don't subscribe to the channel.

com.moviescreenbot.exceptions.authorize.BotAuthorizeException: You don't subscribe to the channel.

at com.moviescreenbot.services.user.UserService.checkSubscriptionForChannel(UserService.java:53) ~[main/:na]
at com.moviescreenbot.services.user.UserService.authorizeUser(UserService.java:24) ~[main/:na]
at com.moviescreenbot.services.user.UserService$$FastClassBySpringCGLIB$$64cf6081.invoke(<generated>) ~[main/:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.20.jar:5.3.20]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) ~[spring-aop-5.3.20.jar:5.3.20]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar:5.3.20]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar:5.3.20]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-5.3.20.jar:5.3.20]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar:5.3.20]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar:5.3.20]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) ~[spring-aop-5.3.20.jar:5.3.20]
at com.moviescreenbot.services.user.UserService$$EnhancerBySpringCGLIB$$6ca7934e.authorizeUser(<generated>) ~[main/:na]

问题排查与解决思路

1. Aspect切面未生效原因

从日志调用链能看到,checkSubscriptionForChannel是被authorizeUser方法内部调用的。Spring AOP默认基于动态代理实现,内部方法调用不会触发切面逻辑——因为此时调用的是目标对象的原生方法,而非代理对象的增强方法,所以切面的环绕通知不会执行。

解决方法:

  • 方案一:把checkSubscriptionForChannel方法迁移到另一个Spring管理的Bean中,通过依赖注入调用,确保走代理对象。
  • 方案二:在当前Bean中注入自身的代理对象,通过代理对象调用目标方法:
    @Service
    public class UserService {
        @Autowired
        private UserService selfProxy;
    
        public void authorizeUser(...) {
            // 使用代理对象调用方法,触发切面
            selfProxy.checkSubscriptionForChannel(chatMember);
        }
    
        @BotExceptionCheck
        public void checkSubscriptionForChannel(ChatMember chatMember) {
            // 原有逻辑
        }
    }
    
  • 方案三:改用AspectJ编译时/加载时织入,替代Spring默认的动态代理,这种方式支持内部方法调用触发切面。

2. 全局异常处理器未生效原因

@ControllerAdvice默认仅处理Spring MVC请求生命周期内Controller层抛出的异常,而你的异常是在Telegram Bot的独立线程[legram Executor]中抛出的,不在Spring MVC的请求处理流程里,所以全局异常处理器无法捕获。

解决方法:

  • 方案一:在Bot的业务处理逻辑中手动添加try-catch,直接捕获并处理异常。
  • 方案二:配置线程级别的异常处理器,捕获所有未处理的线程异常:
    @Configuration
    public class ThreadExceptionConfig {
        @Bean
        public Thread.UncaughtExceptionHandler uncaughtExceptionHandler(SendMessageProducer sendMessageProducer, UserService userService) {
            return (thread, throwable) -> {
                if (throwable instanceof BotAuthorizeException ex) {
                    var user = userService.findById(ex.getChatId());
                    sendMessageProducer.sendMessage(SendMessage.builder()
                            .chatId(user.getChatId())
                            .text(ex.getMessage())
                            .build());
                }
                // 其他异常的处理逻辑
            };
        }
    
        @PostConstruct
        public void setDefaultHandler(Thread.UncaughtExceptionHandler handler) {
            Thread.setDefaultUncaughtExceptionHandler(handler);
        }
    }
    

内容的提问来源于stack exchange,提问作者wanderer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 10:02:02