Можете ли вы использовать свойства @Autowired внутри метода @Async - PullRequest
0 голосов
/ 21 июня 2011

У меня есть некоторый код, который отлично работает без аннотации @Async, но, похоже, не работает с NPE внутри ссылки на @Autowired DAO, когда в методе присутствует @Async.

Вот определение свойств @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) Вызывается код AutoDired lockDAO, который, в свою очередь, пытается извлечь идентификатор пользователя, вошедшего в систему в данный момент, используя код ниже, 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 возвращают нуль после того, как не асинхронный метод, который порождает поток Async, вернулся.

Так как это можно решить. Мои методы блокировки извлекали информацию о пользователе на основе вызова FlexContext.getUserPrinciple. Сначала я думал, что проблема будет решена, сказав Spring распространять контекст безопасности дочерним потокам, как описано здесь: Наследовать контекст безопасности Spring в дочерних потоках , но это не улучшило ситуацию.

Решение оказалось проще, чем я думал, реализовав изменения для распространения контекста безопасности в дочерние потоки, мне просто нужно было изменить метод getCurrentUser () на:

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