Як ввести залежності навесні в об'єкт, що самоаналізується, навесні?


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). Існує також другий метод, за допомогою якого ви можете впливати на те, як відбувається автопроводка
Шон Патрік Флойд

Але що робити, якщо у мене два об’єкти, а перший автопровідний другий. Як фабрика автопровідних бобів справляється із залежностями у випадку?
Вадим Кирильчук

3
Це насправді погана закономірність. Якщо ви справді використовуєте MyBean, чому б просто не створити конструктор з AnotherBean як параметр. Щось на кшталт: codeприватний @Autowired AnotherBean боб; public void doStuff () {MyBean obj = новий MyBean (боб); } code. Схоже, що з усіма цими примітками люди заплутуються і просто не використовують основний зразок, який був у java SDK з першого дня :(
Денис

3
Я згоден - Весна переробила всю мову. Зараз ми використовуємо інтерфейси як конкретні класи, методи як екземпляри класів і всілякі складні та кодові важкі методи робити те, що ви раніше робили з новим та гідним дизайном.
Родні П. Барбаті

@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

Щойно я отримав таку саму потребу, і в моєму випадку до неї вже була логіка всередині не керованого ява класу 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. Ігнорувати боби, коли Spring Bootготовий, використовуючи @Configurableпідхід (використовуючи ApplicationRunner)
  3. Gradle & Eclipse

Кроки

Мені потрібно було виконати наведені нижче кроки, щоб змусити його працювати

  1. Поміщення, @Configurable(preConstruction = true, autowire = Autowire.BY_TYPE, dependencyCheck = false)яке слід розміщувати поверх того, Beanщо повинно бути встановлено вручну. У моєму випадку те, Beanщо має бути встановлено вручну, має @Autowiredпослуги, отже, реквізити вищевказаних анотацій.
  2. Анотація головного весняного завантаження 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(як показано тут мавенцентральне ), але, у моєму випадку, Затемнення не вдалося вирішити @EnableSpringConfiguredанотації, отже, чому я явно додав spring-aopзалежність на додаток до стартера. Якщо ви зіткнулися з одним і тим же питанням, просто оголосьте про залежність або вирушайте у пригоду з'ясування

  • Чи є конфлікт версій
  • Чому org.springframework.context.annotation.aspect.* не доступний
  • Чи правильно налаштовано IDE
  • І т.д.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.