开发者

Can you use @Autowired properties inside an @Async method

开发者 https://www.devze.com 2023-03-14 12:22 出处:网络
I have some code that works fine without the @Async annotation but seems to fail with a NPE inside the reference to the @Autowired DAO when @Async is present on the method.

I have some code that works fine without the @Async annotation but seems to fail with a NPE inside the reference to the @Autowired DAO when @Async is present on the method.

Here's the definition of the @Autowired properties

@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;

And here is the method whic is failing (in the same class).

@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
        Thre开发者_Python百科ad.currentThread().interrupt();
      }
    }
  }

  if (!UtilityClass.isNullOrEmpty(lockUID)) {

Here is a snippet from the stack trace:

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  

Prompted by comments to dig further I did just that and to my shame I discovered the following.

1) The program is not actually crashing or throwing an exception.

2) The Autowired lockDAO code is being called and this in turn tries to retrieve the currently logged in user id using the code below, n.b. I am using Spring Security for authentication and Authorisation.

@Override
public User getCurrentUser()
{
  String name = FlexContext.getUserPrincipal().getName();
  User user = userDAO.findByName(name);
  return user;
}

3) So it is in the code above that I discovered that FlexContext.getUserPrincipal() is returning a null which then causes an InvocationTargetException. Although for some reason I do not understand nothing regarding this InvocationTargetException is written to the log or console.

So it appears that because the method is being called @Async then all the methods of FlexContext return a null after the non Async method that spawns the Async thread has returned.

So how can this be resolved. My locking methods were fetching the user details based on the call to FlexContext.getUserPrinciple. I had initially thought that the problem would be resolved by telling Spring to propagate the security context to child threads as explained here: Inherit Spring Security Context in Child Threads, but that did not improve the situation.

The solution was simpler than I thought, having implemented the changes to propagate the Security Context to child threads I just needed to change my getCurrentUser() method to:

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


Answering at this point of time will be old though, just going through so following check could be helpful if @EnableAsync in there in your @Configuration. Also make sure method 'convertAttachment' invocation should be outside in some other bean.

0

精彩评论

暂无评论...
验证码 换一张
取 消