你可以在@Async 方法中使用@Autowired 属性吗

Posted

技术标签:

【中文标题】你可以在@Async 方法中使用@Autowired 属性吗【英文标题】:Can you use @Autowired properties inside an @Async method 【发布时间】:2011-09-19 05:08:12 【问题描述】:

我有一些代码在没有@Async 注释的情况下可以正常工作,但是当方法上存在@Async 时,似乎在对@Autowired DAO 的引用中出现NPE 失败。

这是@Autowired 属性的定义

@Component
public class DocumentManager implements IDocumentManager 

    private Log logger = LogFactory.getLog(this.getClass());
    private OfficeManager officeManager = null;

    @Autowired
    private IConverterService converterService;

    @Autowired
    private IApplicationProperties applicationProperties;

    @Autowired
    private ILockDAO lockDAO;

    @Autowired
    private IFileAttachmentDAO fileAttachmentDAO;

这是失败的方法(在同一个类中)。

@Async
public void convertAttachment(Integer id) 
  // Now because we are running asynchronously it is likely that the caller
  // to the Create/Update still has a lockUID on this record.
  // We will need our own lockUID before we can update the PDF property

  Long retryInterval = 5000L; // 5 seconds
  Integer retryCount = 5;
  Integer attempts = 0;
  String lockUID = null;

  while (attempts < retryCount && UtilityClass.isNullOrEmpty(lockUID)) 
    attempts++;
    // Seems to go wrong here debugger shows
    ValidationResult result = lockDAO.create(EntityTypeEnum.FILE_ATTACHMENT, id);
    lockUID = lockDAO.getLockUIDFromResult(result);
    if (UtilityClass.isNullOrEmpty(lockUID)) 
      try 
        Thread.sleep(retryInterval);
       catch (InterruptedException e) 
        // http://www.ibm.com/developerworks/java/library/j-jtp05236/index.html
        Thread.currentThread().interrupt();
      
    
  

  if (!UtilityClass.isNullOrEmpty(lockUID)) 

这是堆栈跟踪中的一个 sn-p:

Thread [myExecutor-1] (Suspended)   
InvocationTargetException.<init>(Throwable) line: 54    
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]  
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39  
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25  
Method.invoke(Object, Object...) line: 597  
AopUtils.invokeJoinpointUsingReflection(Object, Method, Object[]) line: 309 
ReflectiveMethodInvocation.invokeJoinpoint() line: 183  
ReflectiveMethodInvocation.proceed() line: 150  
AsyncExecutionInterceptor$1.call() line: 80 
FutureTask$Sync.innerRun() line: 303    
FutureTask<V>.run() line: 138   
ThreadPoolExecutor$Worker.runTask(Runnable) line: 886   
ThreadPoolExecutor$Worker.run() line: 908   
Thread.run() line: 619  

在 cmets 的提示下,我做了进一步的挖掘,但遗憾的是,我发现了以下内容。

1) 程序实际上并没有崩溃或抛出异常。

2) 正在调用 Autowired lockDAO 代码,这反过来又尝试使用下面的代码检索当前登录的用户 ID,n.b。我正在使用 Spring Security 进行身份验证和授权。

@Override
public User getCurrentUser()

  String name = FlexContext.getUserPrincipal().getName();
  User user = userDAO.findByName(name);
  return user;

3) 因此,在上面的代码中,我发现 FlexContext.getUserPrincipal() 返回一个 null,然后导致 InvocationTargetException。尽管出于某种原因,我不明白有关此 InvocationTargetException 被写入日志或控制台的任何内容。

所以看起来因为该方法被调用@Async,所以在产生异步线程的非异步方法返回之后,FlexContext 的所有方法都返回 null。

那么如何解决这个问题。我的锁定方法是根据对 FlexContext.getUserPrinciple 的调用来获取用户详细信息。我最初认为可以通过告诉 Spring 将安全上下文传播到子线程来解决问题,如下所述:Inherit Spring Security Context in Child Threads,但这并没有改善情况。

解决方案比我想象的要简单,实现了将安全上下文传播到子线程的更改,我只需将 getCurrentUser() 方法更改为:

public User getCurrentUser() 
  return (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();

【问题讨论】:

是什么让你猜测它是 Nullpointer 异常? 是什么让您认为涉及convertAttachment 方法? (请向我们展示整个异常跟踪,而不仅仅是随机摘录!) 我在基于 Spring Boot 1.2.RC2 的应用程序中遇到了同样的问题。 @Async 中发生的异常现在被记录(可能 Spring Boot 1.2 默认注册一个 UncaughtExceptionHandler)。您是否找到了有关如何在 @Async 调用的方法中使用 @Autowired 属性的解决方案? 【参考方案1】:

不过,此时回答将是旧的,只是通过因此以下检查可能会有所帮助,如果 @EnableAsync 在您的@Configuration 中。还要确保方法 'convertAttachment' 调用应该在其他 bean 之外。

【讨论】:

以上是关于你可以在@Async 方法中使用@Autowired 属性吗的主要内容,如果未能解决你的问题,请参考以下文章

Symfony 4:“Autowire:你应该明确地配置它的值。”

autowire注解需要加修饰符吗

教你正确打开async/await关键字的使用

从头认识Spring-2.5 @Autowire @Inject @Qualifier @Named的相同与不同

如何在.net4.0中使用.net4.5的async/await实现异步

spring boot+mybatis注解使用方式(无xml配置)设置自动驼峰明明转换(),IDEA中xxDao报错could not autowire的解决方法