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

Spring AOP@Before注解失效与ApplicationContext加载失败问题排查

Spring AOP日志切面实现问题排查与修复

问题背景

学习Spring AOP时,尝试为HelloService类的所有方法实现前置日志切面,使用@Pointcut指向目标类,@Before定义通知方法,但出现ApplicationContext加载失败,且通知未执行的问题。

目标服务类 HelloService

package felim.belajar_aop_spring.service;

import org.springframework.stereotype.Component;

@Component
public class HelloService {

    public String hello(String name){
        return "hello " + name;
    }


    public String bye(String name){
        return "bye " + name;
    }
}

切面类 LogAspect

package felim.belajar_aop_spring.aspect;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LogAspect {

    private static final Logger log = LoggerFactory.getLogger(LogAspect.class);

    @Pointcut("target(felim.belajar_aop_spring.service.HelloService)")
    public void helloLog() {
    }

    @Before("helloLog()")
    public void beforeHelloService() {
        log.info("yo");
    }
}

错误详情

java.lang.IllegalStateException: 无法为[MergedContextConfiguration@692fd26 testClass = felim.belajar_aop_spring.HelloServiceTest, locations = [], classes = [felim.belajar_aop_spring.BelajarAopSpringApplication], contextInitializerClasses = [], activeProfiles = [], propertySourceDescriptors = [], propertySourceProperties = ["org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true"], contextCustomizers = [org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@22ef9844, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@1da2cb77, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@306e95ec, org.springframework.boot.test.autoconfigure.OnFailureConditionReportContextCustomizerFactory$OnFailureConditionReportContextCustomizer@1b2abca6, org.springframework.boot.test.autoconfigure.actuate.observability.ObservabilityContextCustomizerFactory$DisableObservabilityContextCustomizer@1f, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizer@6253c26, org.springframework.test.context.support.DynamicPropertiesContextCustomizer@0, org.springframework.boot.test.context.SpringBootTestAnnotation@726aa670], contextLoader = org.springframework.boot.test.context.SpringBootContextLoader, parent = null]加载ApplicationContext

    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:180)
    at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:130)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:142)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:98)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:260)
    at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:160)
    at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:215)
    at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:197)
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:215)
    at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1709)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:570)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:560)
    at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
    at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:265)
    at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:636)
    at java.base/java.util.Optional.orElseGet(Optional.java:364)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1597)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1597)
Caused by: org.springframework.beans.factory.BeanCreationException: 创建名为'org.springframework.test.context.support.internalDynamicPropertyRegistrarBeanInitializer'的Bean失败:Bean实例化前的BeanPostProcessor执行失败
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:518)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:336)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:289)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:334)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:963)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:627)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:439)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:318)
    at org.springframework.boot.test.context.SpringBootContextLoader.lambda$loadContext$3(SpringBootContextLoader.java:137)
    at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:58)
    at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:46)
    at org.springframework.boot.SpringApplication.withHook(SpringApplication.java:1461)
    at org.springframework.boot.test.context.SpringBootContextLoader$ContextLoaderHook.run(SpringBootContextLoader.java:553)
    at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:137)
    at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:108)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:225)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:152)
    ... 19 more
Caused by: java.lang.NoClassDefFoundError: org/aspectj/weaver/reflect/ReflectionWorld$ReflectionWorldException
    at org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory.getPointcut(ReflectiveAspectJAdvisorFactory.java:236)
    at org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory.getAdvisor(ReflectiveAspectJAdvisorFactory.java:210)
    at org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory.getAdvisors(ReflectiveAspectJAdvisorFactory.java:146)
    at org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder.buildAspectJAdvisors(BeanFactoryAspectJAdvisorsBuilder.java:116)
    at org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors(AnnotationAwareAspectJAutoProxyCreator.java:95)
    at org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator.shouldSkip(AspectJAwareAdvisorAutoProxyCreator.java:105)
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessBeforeInstantiation(AbstractAutoProxyCreator.java:280)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInstantiation(AbstractAutowireCapableBeanFactory.java:1150)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.resolveBeforeInstantiation(AbstractAutowireCapableBeanFactory.java:1125)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:512)
    ... 37 more
Caused by: java.lang.ClassNotFoundException: org/aspectj/weaver/reflect/ReflectionWorld$ReflectionWorldException
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:528)
    ... 47 more

问题排查与修复

1. 核心问题:缺失AspectJ依赖

从错误栈的NoClassDefFoundError: org/aspectj/weaver/reflect/ReflectionWorld$ReflectionWorldException可以看出,项目缺少AspectJ Weaver的依赖,导致Spring无法解析AspectJ的切入点表达式。

修复步骤

Maven项目

在pom.xml中添加AspectJ相关依赖:

<dependencies>
    <!-- Spring AOP 基础依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    <!-- AspectJ Weaver,用于解析AspectJ表达式 -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <scope>runtime</scope>
    </dependency>
</dependencies>

Gradle项目

在build.gradle中添加:

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-aop'
    runtimeOnly 'org.aspectj:aspectjweaver'
}

2. 切面代码优化(可选)

当前切入点target(felim.belajar_aop_spring.service.HelloService)可以正常工作,但如果需要更精准匹配该类的所有方法,可以修改切入点表达式:

@Pointcut("target(felim.belajar_aop_spring.service.HelloService) && execution(* *(..))")
public void helloLog() {}

或者使用within表达式,匹配类内部的所有方法:

@Pointcut("within(felim.belajar_aop_spring.service.HelloService)")
public void helloLog() {}

另外,通知方法可以添加连接点参数,获取更多方法调用信息:

import org.aspectj.lang.JoinPoint;
import java.util.Arrays;

// ...

@Before("helloLog()")
public void beforeHelloService(JoinPoint joinPoint) {
    String methodName = joinPoint.getSignature().getName();
    Object[] args = joinPoint.getArgs();
    log.info("调用HelloService的{}方法,参数:{}", methodName, Arrays.toString(args));
}

3. 确认自动代理配置

Spring Boot中,添加spring-boot-starter-aop依赖后,会自动启用@EnableAspectJAutoProxy,无需手动配置。如果是传统Spring项目,需要在配置类上添加@EnableAspectJAutoProxy注解。

Spring AOP日志最佳实践

  • 依赖管理:优先使用spring-boot-starter-aop,它会自动引入必要的Spring AOP和AspectJ基础依赖,避免手动依赖冲突。
  • 切入点精准性:根据需求选择合适的切入点表达式:
    • within:匹配指定包/类下的所有方法
    • execution:精准匹配方法签名(返回值、类、方法名、参数)
    • target:匹配实现指定接口的类或指定类本身的实例
  • 通知参数利用:通过JoinPoint获取方法签名、参数、目标对象等信息,让日志更具可读性和排查价值。
  • 切面职责单一:一个切面只负责一类逻辑(如日志、权限、事务),避免切面臃肿。
  • 避免过度AOP:不要对所有方法都添加切面,只对需要监控的业务方法、对外接口等进行切面增强,避免性能损耗。
  • 日志级别合理:根据日志内容选择合适的级别,如方法调用用INFO,异常用ERROR,调试信息用DEBUG。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 03:04:51