【问题标题】:Spring @Async @Autowired null in only one methodSpring @Async @Autowired null 仅在一种方法中
【发布时间】:2016-03-18 04:20:40
【问题描述】:

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

@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 的事件时,会调用TemplateServicetoString() 方法(如我所料)。我可能误解了@Async 如何影响@Autowired 对象的某些方面,但我无法确定那会是什么。我在滥用@Async 吗?我是否误解了如何在多线程环境中使用 @Autowired 对象?

【问题讨论】:

  • 您的类没有实现接口,这意味着它不能被考虑用于类路径扫描。你没有滥用异步。
  • @JamesENL 我不确定你的意思。 templateService 连接在 listener2 中,因此 Spring 上下文必须知道该类。我要实现什么接口?
  • 你的监听器上没有接口,所以 Spring 不知道它是一个类,也不能创建一个代理来创建 Async 方法。
  • @JamesENL 我真的不明白你的意思。你是说Spring只能知道实现any接口的类?
  • 默认情况下是的(有办法绕过它,但这不相关),你需要有一个接口,它应该定义这个类应该实现的 listener1 和 listener2。

标签: spring multithreading asynchronous autowired


【解决方案1】:

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

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

改变你的方法

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

【讨论】:

    【解决方案2】:

    Spring 需要一个接口来创建代理类。每次调用方法时都会调用这个代理类,整个异步执行都是通过这个方法发生的。如果没有接口,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 不能异步运行私有方法。

    【讨论】:

    • 不需要组件必须实现接口以便Spring可以代理它。这是一种推荐的做法,但如果组件没有实现至少一个接口,Spring 仍然可以使用基于 CGLIB 类的代理。但是,您在方法可见性方面是正确的。 @Async 方法必须对子类可见,以便 Spring 可以在代理类中覆盖它。要拦截您的方法以便在单独的线程中运行,Spring 必须覆盖您的方法以编织新行为
    猜你喜欢
    • 2014-12-15
    • 2015-08-07
    • 2018-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-19
    相关资源
    最近更新 更多