Почему Autowiring не работает в потоке?

Я сделал проект maven в Spring 3.0, я сделал несколько DAO, сервисов и контроллеров, в одном из моих контроллеров я вызываю сервис, в котором запускаю поток, проблема в том, что в потоке я объявляю «сервис переменная", которая должна быть инициализирована с помощью аннотации Autowired, но она не работает, и переменная не инициализирована и имеет значение null.

это класс потока

package com.project.tasks;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;

import com.project.entities.user.User;
import com.project.services.IUserService;

@Component
public class AddFriendInMyFriendListTaskExecutor {
private class AddFriendInMyFriendListTask implements Runnable {


     // HERE IS THE PROBLEM
    @Autowired
    private IUserService uService;

    private User a;
    private User b;

    public AddFriendInMyFriendListTask() {
        ;
    }

    public AddFriendInMyFriendListTask(User aA, User bB) {
        a = aA;
        b = bB;
    }

    public User getA() {
        return a;
    }
    public void setA(User a) {
        this.a = a;
    }
    public User getB() {
        return b;
    }
    public void setB(User b) {
        this.b = b;
    }


    public void run() {
                    // FROM HERE IT PRINTS THE VALUE OF uService THAT IS NULL
        System.out.println("uService:" + uService);
        uService.insertRightUserIntoLeftUserListOfFriends(a, b);
    }
}

private TaskExecutor taskExecutor;

  public AddFriendInMyFriendListTaskExecutor(TaskExecutor taskExecutor) {
    this.taskExecutor = taskExecutor;
  }

  public void doIt(User a, User b) {
      taskExecutor.execute(new AddFriendInMyFriendListTask(a, b));
  }
}

это фрагмент кода, который вызывает поток

    User a = uDao.getUser(hrA.getMyIdApp());
    User b = uDao.getUser(hrA.getOtherIdApp());
    SimpleAsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor();
    AddFriendInMyFriendListTaskExecutor tmp = new AddFriendInMyFriendListTaskExecutor(taskExecutor);
    tmp.doIt(a, b);

Я хотел бы подчеркнуть, что во всех других тестах, в которых я не вызываю никаких потоков, Autowired экземпляра UserService работает правильно! Метод, который я вызываю: insertRightUserIntoLeftUserListOfFriends(User a, User b), работает корректно.


person user942458    schedule 13.09.2011    source источник


Ответы (5)


Для автоматического связывания bean-компонента Spring, bean-компонент должен быть bean-компонентом Spring (т. е. быть объявленным в файле context.xml или иметь аннотацию Spring (@Service, @Component и т. д.).

И, конечно же, он должен быть создан Spring, а не вашим кодом. Если вы сами создаете экземпляр компонента Spring с помощью new, Spring ничего не знает о компоненте и ничего в него не внедряет.

person JB Nizet    schedule 13.09.2011
comment
Нет. Вы создаете экземпляр AddFriendInMyFriendListTaskExecutor с помощью new AddFriendInMyFriendListTaskExecutor(), внутренний класс AddFriendInMyFriendListTask (который должен быть статическим) не аннотируется, и вы также создаете его с помощью new. - person JB Nizet; 13.09.2011
comment
Извините, возможно, я не понимаю вашего ответа или не могу объяснить свою проблему, создание экземпляра AddFriendInMyFriendListTaskExecutor не доставляет мне никаких проблем, фактически после кода: AddFriendInMyFriendListTaskExecutor tmp = new AddFriendInMyFriendListTaskExecutor(taskExecutor); tmp не равен нулю, проблема в том, что когда я использую uService в классе AddFriendInMyFriendListTask, нет проблем с калссой и инициализацией экземпляров AddFriendInMyFriendListTask. - person user942458; 13.09.2011
comment
Spring должен создавать экземпляры spring bean-компонентов. Не вы. Вы не можете использовать новый оператор для создания экземпляров Spring Bean. Они должны быть либо введены в текущий бин с помощью Spring, либо вы должны получить их с фабрики бинов. - person JB Nizet; 13.09.2011

Spring просто автоматически подключает bean-компоненты контекста, новые экземпляры не создаются. Но почему вы объявили uService в AddFriendInMyFriendListTask, а не как свойство bean-компонента внешнего (bean) класса AddFriendInMyFriendListTaskExecutor, это должно просто работать:

@Component
public class AddFriendInMyFriendListTaskExecutor {

  private class AddFriendInMyFriendListTask implements Runnable {

    private final User a;
    private final User b;

    public AddFriendInMyFriendListTask(User aA, User bB) {
      a = aA;
      b = bB;
    }

    public void run() {
      AddFriendInMyFriendListTaskExecutor.this.uService.insertRightUserIntoLeftUserListOfFriends(a, b);
    }
  }

  @Autowired
  private IUserService uService;

  @Autowired
  private TaskExecutor taskExecutor;

  public void doIt(User a, User b) {
    taskExecutor.execute(new AddFriendInMyFriendListTask(a, b));
  }
}

(удален некоторый неиспользуемый геттер/сеттер и сделан taskExecutor также свойством bean-компонента)

person Arne Burmeister    schedule 13.09.2011

Если вам нужно автоматически связать вновь созданный экземпляр (без поддержки контейнера), вызовите

ctx.getAutowireCapableBeanFactory().autowireBean(экземпляр)

где ctx — это ваш ApplicationContext, а instance — только что созданный экземпляр.

Я задал аналогичный вопрос здесь

person stacker    schedule 13.09.2011

Другим решением было бы внедрить пользователя IUserService в управляемый компонент Spring (сервис, компонент и т. д.) и передать введенное значение конструктору класса AddFriendInMyFriendListTask.

Таким образом, конструктор становится примерно таким

public AddFriendInMyFriendListTask(User aA, User bB, IUserService userService) {
    a = aA;
    b = bB;
    this.userService = userService;
}

и удалите @Autowired из класса AddFriendInMyFriendListTask.

person aseychell    schedule 13.09.2011

Была похожая проблема, пришлось Autowire в сервисе и переходить к методу, который реализует runnable через конструктор.

person Xcoder    schedule 08.07.2015