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

时间:2011-06-21 04:52:26

标签: android spring asynchronous android-asynctask blazeds

我有一些代码在没有@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)) {

以下是堆栈跟踪的片段:

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  

通过评论进一步深入挖掘,我做到了这一点而且我感到羞耻,我发现了以下内容。

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

2)正在调用自动​​连接的lockDAO代码,这反过来尝试使用下面的代码n.b.检索当前登录的用户ID。我正在使用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的所有方法在产生Async线程的非Async方法返回后返回null。

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

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

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

1 个答案:

答案 0 :(得分:0)

虽然此时的回答会过时,但如果进行以下检查可能会有所帮助 @EnableAsync 在您的@Configuration 中。还要确保方法 'convertAttachment' 调用应该在其他 bean 的外部。