Самостоятельная инъекция с пружиной - PullRequest
57 голосов
/ 01 марта 2011

Я попробовал следующий код с Spring 3.x, который потерпел неудачу с BeanNotFoundException, и он должен соответствовать ответам на вопрос, который я задавал ранее - Могу ли я ввести тот же класс с помощью Spring?

@Service
public class UserService implements Service{
    @Autowired
    private Service self;
}

Поскольку я пробовал это с Java 6, я обнаружил, что следующий код работает нормально:

@Service(value = "someService")
public class UserService implements Service{
    @Resource(name = "someService")
    private Service self;
}

но я не понимаю, как это разрешает циклическую зависимость.

EDIT:
Вот сообщение об ошибке. ФП упомянул об этом в комментарии к одному из ответов:

Вызвано: org.springframework.beans.factory.NoSuchBeanDefinitionException: не найден соответствующий компонент типа [com.spring.service.Service] для зависимости: ожидается, что по крайней мере 1 компонент, который квалифицируется как кандидат для автоматического подключения для этой зависимости. Аннотации зависимостей: {@ org.springframework.beans.factory.annotation.Autowired (обязательно = true)}

Ответы [ 7 ]

43 голосов
/ 09 марта 2011

Обновление: февраль 2016 г.

Самостоятельная автоматическая разводка будет официально поддерживаться в Spring Framework 4.3.Реализацию можно увидеть в этом коммите GitHub .


. Определенная причина, по которой вы не можете самостоятельно подключаться, заключается в том, что реализация метода Spring * DefaultListableBeanFactory.findAutowireCandidates(String, Class, DependencyDescriptor) явно исключает такую ​​возможность.Это видно из следующей выдержки из этого метода:

for (String candidateName : candidateNames) {
    if (!candidateName.equals(beanName) && isAutowireCandidate(candidateName, descriptor)) {
        result.put(candidateName, getBean(candidateName));
    }
}

FYI: имя компонента (т. Е. Компонента, который пытается автоматически подключиться) - beanName.Этот бин на самом деле является кандидатом autowire, но вышеприведенное условие if возвращает false (поскольку candidateName фактически равно beanName).Таким образом, вы просто не можете автоматически связывать бин с самим собой (по крайней мере, не начиная с Spring 3.1 M1).

Теперь о том, является ли это предполагаемым поведением семантически говоря, это другой вопрос.;)

Я спрошу Юргена и посмотрю, что он скажет.

С уважением,

Сэм (Core Spring Committer)

ps I 'Мы открыли проблему Spring JIRA, чтобы рассмотреть возможность поддержки самостоятельной автопроводки по типу с использованием @Autowired.Не стесняйтесь смотреть или голосовать за эту проблему здесь: https://jira.springsource.org/browse/SPR-8450

34 голосов
/ 01 марта 2011

Этот код тоже работает:

@Service
public class UserService implements Service {

    @Autowired
    private ApplicationContext applicationContext;

    private Service self;

    @PostConstruct
    private void init() {
        self = applicationContext.getBean(UserService.class);
    }
}

Я не знаю почему, но кажется, что Spring может получить бин из ApplicationContext, если создан , но не инициализирована .@Autowired работает до инициализации и не может найти тот же компонент.Итак, @Resource может работать после @Autowired и до @PostConstruct.

Но я не знаю, просто спекулировать.В любом случае, хороший вопрос.

1 голос
/ 16 октября 2013

Получить прокси AOP от самого объекта вопрос предлагает альтернативный хакерский подход с AopContext.currentProxy(), который может подойти для особых случаев.

1 голос
/ 09 марта 2011

Кстати, более элегантное решение проблемы самовывоза - использовать AspectJ Load-Time Weaving для ваших транзакционных прокси (или любого другого прокси-сервера, представленного вами в AOP).

Например, при управлении транзакциями на основе аннотаций вы можете использовать режим «aspectj» следующим образом:

<tx:annotation-driven mode="aspectj" />

Обратите внимание, что режимом по умолчанию является "прокси" (т. Е. Динамические прокси JDK).

С уважением,

Sam

1 голос
/ 01 марта 2011

Приведенный выше код я не вижу циклической зависимости.Вы внедрили какой-то экземпляр Сервиса в UserService.Реализация внедренной службы не обязательно должна быть другой UserService, поэтому циклическая зависимость отсутствует.

Я не понимаю, почему вы добавили бы UserService в UserService, но я надеюсь, что это теоретическая попыткаили такой.

0 голосов
/ 21 декабря 2018

Просто еще один подход:

@EnableAsync
@SpringBootApplication
public class Application {

    @Autowired
    private AccountStatusService accountStatusService;

    @PostConstruct
    private void init() {
        accountStatusService.setSelf(accountStatusService);
    }
}

@Service
public class AccountStatusService {
    private AccountStatusService self;

    public void setSelf(AccountStatusService self) {
        this.self = self;
    }
}

с этим ваш сервис будет в прокси.Я сделал это для работы с асинхронными методами внутри себя.

Я попытался @sinuhepop решение:

@PostConstruct
private void init() {
    self = applicationContext.getBean(UserService.class);
}

Он сделал инъекцию, но служба не была внутри прокси и мои методы не былиработает в новой теме.При таком подходе он работает так, как мне бы хотелось.

0 голосов
/ 01 марта 2011

Похоже, что Spring создает и настраивает объект, а затем помещает его в контекст поиска компонента. Но, в случае Java, я думаю, что он создает объект и связывает его с именем и во время конфигурации, когда объект ищется по имени, которое он нашел в контексте.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...