Spring @Async @Autowired null 只有一种方法

Spring @Async @Autowired null in only one method

我在我的 Spring 应用程序中调用自动装配对象的方法时遇到 NullPointerException。有问题的 class 如下所示:

@Component
public class Listener {

  @Autowired
  TemplateService templateService;

  @Async
  @EventListener
  private Future<String> listener1(Event1 event) {
    System.out.println(templateService);
    return new AsyncResult<>(null);
  }

  @Async
  @EventListener
  public Future<String> listener2(Event2 event) {
    System.out.println(templateService);
    return new AsyncResult<>(null);
  }
}

当我发布触发 listener1 的事件时,会打印一个 null 值,但是当我发布触发 listener2 的事件时,toString() 方法TemplateService 被调用(如我所料)。我可能误解了 @Async 如何影响 @Autowired 对象的某些方面,但我无法确定那是什么。我在滥用 @Async 吗?我是否误解了如何在多线程环境中使用 @Autowired 对象?

Spring 需要一个接口来创建代理 class。每次调用该方法时都会调用此代理 class,整个异步执行都是通过此方法发生的。没有接口 Spring 无法自动装配、扫描或使方法异步执行。

public interface Listener { 

    public Future<String> listener1(Event1 event);
    public Future<String> listener2(Event2 event);
}

@Component
public class ListenerImpl { 

    @Autowired
    private TemplateService templateService;

    @Async
    @Override
    public Future<String> listener1(Event1 event) {
        System.out.println(templateService);
        return new AsyncResult<>(null);
    }

    @Async
    @Override
    public Future<String> listener2(Event2 event) {
        System.out.println(templateService);
        return new AsyncResult<>(null);
    }
}

还值得注意的是 Spring 不能 运行 异步私有方法。

将 listener1 方法的可见性更改为至少受保护(包可见性、受保护或 public)。这是因为 Spring 创建了一个代理,它是您组件的一个子类。它会覆盖您的 @Async 注释方法,以便添加新逻辑以在单独的线程中执行您的代码。但是因为它使用继承它只能覆盖子类可见的方法。

这解释了为什么 public 的 listener2 方法有效。

将您的方法更改为

@Async
  @EventListener
  public Future<String> listener1(Event1 event) {
    System.out.println(templateService);
    return new AsyncResult<>(null);
  }