Как внедрить зависимости в самопроизвольный объект в Spring?


128

Допустим, у нас есть класс:

public class MyClass {
    @Autowired private AnotherBean anotherBean;
}

Затем мы создали объект этого класса (или какой-то другой фреймворк создал экземпляр этого класса).

MyClass obj = new MyClass();

Можно ли по-прежнему внедрять зависимости? Что-то вроде:

applicationContext.injectDependencies(obj);

(Думаю, у Google Guice есть что-то вроде этого)

Ответы:


194

Сделать это можно с помощью autowireBean()метода AutowireCapableBeanFactory. Вы передаете ему произвольный объект, и Spring будет относиться к нему как к чему-то, что он создал сам, и применит различные части и части автоподключения.

Чтобы получить AutowireCapableBeanFactoryдоступ, просто подключите следующее:

private @Autowired AutowireCapableBeanFactory beanFactory;

public void doStuff() {
   MyBean obj = new MyBean();
   beanFactory.autowireBean(obj);
   // obj will now have its dependencies autowired.
}

Хороший ответ (+1). Также есть второй метод, с помощью которого вы можете повлиять на то, как происходит автоматическое
— Шон Патрик Флойд

Но что, если у меня есть два объекта, а второй - автопроволока. Как autowire bean factory справляется с зависимостями в кейсе?
— Вадим Кирильчук

3
На самом деле это плохой образец. Если это то, как вы действительно используете MyBean, почему бы просто не иметь конструктор с параметром AnotherBean в качестве параметра. Что-то вроде: codeчастный компонент @Autowired AnotherBean; public void doStuff () {MyBean obj = новый MyBean (bean); } code. Похоже, что со всеми этими аннотациями люди действительно сбиваются с толку и просто не используют базовый шаблон, который был в java SDK с первого дня. :(
— Денис

3
Я согласен - Spring полностью изменил определение языка. Теперь мы используем интерфейсы как конкретные классы, методы как экземпляры классов и всевозможные сложные и тяжелые методы выполнения того, что вы делали раньше, с новым и достойным дизайном.
— Родни П. Барбати

@Denis, если MyBean имеет зависимости, которые фактическому классу не нужны, вы регистрируете зависимости, которых на самом деле не существует, просто для создания экземпляра класса, поэтому на самом деле нет никакой разницы.
— Далтон

17

Вы также можете пометить свой MyClass аннотацией @Configurable:

@Configurable
public class MyClass {
   @Autowired private AnotherClass instance
}

Затем во время создания он автоматически внедрит свои зависимости. У вас также должен быть <context:spring-configured/>в контексте вашего приложения xml.


2
Galz666, ваш метод выглядит намного чище для того, что я хочу сделать. Однако я не могу заставить его работать. У меня нет XML-файла, и я использую полностью конфигурацию Java. Есть ли эквивалент <context:spring-configured/>?
— masstroy

1
Это чистое решение, но требует немного больше усилий: вы должны либо использовать переплетение во время загрузки, как показано выше iimuhin, либо добавить компилятор AspectJ в проект. Время загрузки, как следует из названия, вызовет дополнительные затраты во время выполнения.
— jsosnowski

4

Просто возникла такая же потребность, и в моем случае это уже была логика внутри управляемого java-класса, отличного от Spring, к которому был доступ ApplicationContext. В стиле эшафот. Решено:

AutowireCapableBeanFactory factory = applicationContext.getAutowireCapableBeanFactory();
factory.autowireBean(manuallyCreatedInstance);

3

Я хотел поделиться своим решением, которое следует @Configurableподходу, brieflyупомянутому в ответе @ glaz666, потому что

  • Ответ на @skaffman почти 10 лет, и это не означает , что не достаточно хорошо или не работает
  • Ответ @ glaz666 краток и на самом деле не помог мне решить мою проблему, но указал мне правильное направление

Моя установка

  1. Spring Boot 2.0.3 с Spring Neo4j & Aop starts(что в любом случае не имеет значения)
  2. Создайте экземпляр bean-компонента, когда он Spring Bootбудет готов, используя @Configurableподход (using ApplicationRunner)
  3. Gradle и Eclipse

меры

Мне нужно было выполнить следующие шаги, чтобы заставить его работать

  1. Объект @Configurable(preConstruction = true, autowire = Autowire.BY_TYPE, dependencyCheck = false)должен быть помещен поверх вашего, Beanкоторый должен быть создан вручную. В моем случае Beanэкземпляр, который должен быть создан вручную, имеет @Autowiredслужбы, следовательно, реквизиты для указанной выше аннотации.
  2. Аннотируйте основную часть Spring Boot XXXApplicaiton.java(или файл, помеченный @SpringBootApplication) с помощью @EnableSpringConfiguredи@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.ENABLED)
  3. Добавьте зависимости в свой файл сборки (например, build.gradle или pom.xml в зависимости от того, какой из них вы используете) compile('org.springframework.boot:spring-boot-starter-aop')иcompile('org.springframework:spring-aspects:5.0.7.RELEASE')
  4. Новый + ваш, Beanкоторый аннотирован @Configurableгде угодно, и его зависимости должны быть автоматически подключены.

* Что касается пункта 3 выше, я знаю, что org.springframework.boot:spring-boot-starter-aopтранзитивно тянет spring-aop(как показано здесь mavencentral ), но в моем случае Eclipse не смог разрешить @EnableSpringConfiguredаннотации, поэтому я явно добавил spring-aopзависимость в дополнение к стартеру. Если вы столкнетесь с той же проблемой, просто объявите о зависимости или отправляйтесь на поиски решения

  • Есть ли конфликт версий
  • Почему org.springframework.context.annotation.aspect.*недоступен
  • Правильно ли настроена ваша IDE?
  • И т. Д. И т. Д.
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.