JMH基准测试在Spring(使用Maven)项目中的Autowired字段中出现NullPointerException异常

8

我尝试对我的Spring(使用Maven构建的)项目中的一些方法进行基准测试。我需要在我的项目中的几个字段上使用@Autowired和@Inject。当我运行我的项目时,它可以正常工作。但是,在使用@Autowired/@Inject字段时,JMH总是会出现NullPointerException错误。

public class Resources {

    private List<Migratable> resources;

    @Autowired
    public void setResources(List<Migratable> migratables) {
        this.resources = migratables;
    }

    public Collection<Migratable> getResources() {
        return resources;
    }
}

我的基准测试类

@State(Scope.Thread)
public class MyBenchmark {

    @State(Scope.Thread)
    public static class BenchmarkState {

        Resources res;

        @Setup
        public void prepare() {
            res = new Resources();
        }
    }

    @Benchmark
    public void testBenchmark(BenchmarkState state, Blackhole blackhole) {
        blackhole.consume(state.res.getResources());
    }
}

当我运行我的基准测试时,在Resources.getResources()处出现了空指针异常,更具体地说是在resources处。
它无法自动装配setResources()。但是,如果我运行我的项目(不包括基准测试),它可以正常工作。
如何在进行基准测试时消除这个Autowired字段的空指针异常?


1
你有找到解决方案吗? - timbre timbre
2个回答

0
这是一个关于如何运行基于Spring的基准测试的示例:https://github.com/stsypanov/spring-boot-benchmark
基本上,你需要将应用程序上下文的引用存储为基准测试类的字段,在@Setup方法中初始化上下文,并在@TearDown中关闭它。就像这样:
@State(Scope.Thread)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@BenchmarkMode(value = Mode.AverageTime)
public class ProjectionVsDtoBenchmark {

  private ManyFieldsRepository repository;

  private ConfigurableApplicationContext context;

  @Setup
  public void init() {
    context = SpringApplication.run(Application.class);
    context.registerShutdownHook();

    repository = context.getBean(ManyFieldsRepository.class);
  }

  @TearDown
  public void closeContext(){
    context.close();
  }
}

你要测量的逻辑必须封装在一个 Spring 组件的方法中,该方法将从带有 @Benchmark 注释的方法调用。请记住基准测试的一般规则,以确保您的测量正确,例如使用 Blackhole 或从方法返回值,以防止编译器进行 DCE 优化。


-1

尝试在测试类上使用@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations = {...})。这将初始化Spring TestContext Framework并允许您自动装配依赖项。

如果这不起作用,则必须在您的@Setup注释方法中显式启动Spring ApplicationContext,使用以下任一方法,并从该上下文解析bean:

ClassPathXmlApplicationContext、FileSystemXmlApplicationContext或WebXmlApplicationContext

ApplicationContext context = new ChosenApplicationContext("path_to_your_context_location");
res = context.getBean(Resources.class);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接