Wie füge ich im Frühjahr Abhängigkeiten in ein selbstinstanziiertes Objekt ein?

128

Nehmen wir an, wir haben eine Klasse:

public class MyClass {
    @Autowired private AnotherBean anotherBean;
}

Dann haben wir ein Objekt dieser Klasse erstellt (oder ein anderes Framework hat die Instanz dieser Klasse erstellt).

MyClass obj = new MyClass();

Ist es möglich, die Abhängigkeiten noch zu injizieren? Etwas wie:

applicationContext.injectDependencies(obj);

(Ich denke, Google Guice hat so etwas)

Igor Mukhin
quelle

Antworten:

194

Sie können dies mit der autowireBean()Methode von tun AutowireCapableBeanFactory. Sie übergeben ihm ein beliebiges Objekt, und Spring behandelt es wie etwas, das es selbst erstellt hat, und wendet die verschiedenen automatisch verdrahteten Teile an.

Um das zu erreichen AutowireCapableBeanFactory, verdrahten Sie einfach Folgendes:

private @Autowired AutowireCapableBeanFactory beanFactory;

public void doStuff() {
   MyBean obj = new MyBean();
   beanFactory.autowireBean(obj);
   // obj will now have its dependencies autowired.
}
Skaffman
quelle
Gute Antwort (+1). Es gibt auch eine zweite Methode, mit der Sie beeinflussen können, wie das automatische Verdrahten
Sean Patrick Floyd
Aber was ist, wenn ich zwei Objekte habe und erstens das zweite automatisch verdrahtet? Wie geht die Autowire Bean Factory mit Abhängigkeiten im Fall um?
Vadim Kirilchuk
3
Dies ist eigentlich ein schlechtes Muster. Wenn Sie MyBean auf diese Weise wirklich verwenden, haben Sie nicht einfach einen Konstruktor mit AnotherBean als Parameter. So etwas wie: codeprivate @Autowired AnotherBean Bean; public void doStuff () {MyBean obj = neue MyBean (Bean); } code. Scheint wie bei all diesen Anmerkungen zu sein, die Leute sind wirklich verwirrt und verwenden einfach nicht das Grundmuster, das seit Tag 1 im Java SDK war. :(
Denis
3
Ich stimme zu - Spring hat die gesamte Sprache neu definiert. Jetzt verwenden wir Schnittstellen als konkrete Klassen, Methoden als Klasseninstanzen und alle Arten von komplizierten und codeintensiven Methoden, um das zu tun, was Sie früher mit neuem und anständigem Design getan haben.
Rodney P. Barbati
@Denis Wenn MyBean Abhängigkeiten hat, die die eigentliche Klasse nicht benötigt, registrieren Sie Abhängigkeiten, die nicht tatsächlich existieren, nur um eine Klasse zu instanziieren. Es gibt also wirklich keinen Unterschied.
Dalton
17

Sie können Ihre MyClass auch mit der Anmerkung @Configurable markieren:

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

Zum Zeitpunkt der Erstellung werden dann automatisch die Abhängigkeiten eingefügt. Sie sollten auch <context:spring-configured/>in Ihrem Anwendungskontext XML haben.

glaz666
quelle
2
Galz666, Ihre Methode sieht viel sauberer aus für das, was ich tun möchte. Ich kann es jedoch nicht zum Laufen bringen. Ich habe keine XML-Datei und verwende ausschließlich Java-Konfiguration. Gibt es ein Äquivalent zu <context:spring-configured/>?
Masstroy
1
Dies ist eine saubere Lösung, erfordert jedoch etwas mehr Aufwand: Sie sollten entweder das Laden in der Ladezeit verwenden, wie oben gezeigt, oder den AspectJ-Compiler zum Projekt hinzufügen. Die Ladezeit, wie der Name schon sagt, verursacht zur Laufzeit zusätzliche Kosten.
Jsosnowski
4

Ich habe gerade das gleiche Bedürfnis bekommen und in meinem Fall war es bereits die Logik innerhalb der nicht Spring verwaltbaren Java-Klasse, auf die Zugriff hatte ApplicationContext. Inspiriert von Scaffman. Gelöst von:

AutowireCapableBeanFactory factory = applicationContext.getAutowireCapableBeanFactory();
factory.autowireBean(manuallyCreatedInstance);
rand0m86
quelle
3

Ich wollte meine Lösung teilen, die dem @ConfigurableAnsatz folgt, wie brieflyin @ glaz666 Antwort erwähnt, weil

  • Die Antwort von @skaffman ist fast 10 Jahre alt, und das bedeutet nicht, dass es nicht gut genug ist oder nicht funktioniert
  • Die Antwort von @ glaz666 ist kurz und hat mir nicht wirklich geholfen, mein Problem zu lösen, hat mich aber in die richtige Richtung gelenkt

Mein Setup

  1. Spring Boot 2.0.3 mit Spring Neo4j & Aop starts(was sowieso irrelevant ist)
  2. Instanziieren Sie eine Bohne, wenn sie Spring Bootmit dem @ConfigurableAnsatz (using ApplicationRunner) fertig ist.
  3. Gradle & Eclipse

Schritte

Ich musste die folgenden Schritte ausführen, damit es funktioniert

  1. Die @Configurable(preConstruction = true, autowire = Autowire.BY_TYPE, dependencyCheck = false)auf Ihre zu platzierende Bean, die manuell instanziiert werden soll. In meinem Fall haben die Beanzu instanziierenden, zu instanziierenden @AutowiredDienste daher die Requisiten zur obigen Anmerkung.
  2. Kommentieren Sie das Hauptmenü des Spring Boot XXXApplicaiton.java(oder die mit Anmerkungen versehene Datei @SpringBootApplication) mit @EnableSpringConfiguredund@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.ENABLED)
  3. Fügen Sie die Abhängigkeiten in Ihre Build-Datei ein (dh build.gradle oder pom.xml, je nachdem, welche Sie verwenden) compile('org.springframework.boot:spring-boot-starter-aop')undcompile('org.springframework:spring-aspects:5.0.7.RELEASE')
  4. Neu + up Ihr Bean, das mit @Configurableirgendwo kommentiert ist und dessen Abhängigkeiten automatisch verdrahtet werden sollten.

* In Bezug auf Punkt 3 oben ist mir bewusst, dass das org.springframework.boot:spring-boot-starter-aoptransitiv das spring-aop(wie hier gezeigt mavencentral ) zieht, aber in meinem Fall konnte die Eclipse die @EnableSpringConfiguredAnnotationen nicht auflösen , weshalb ich die spring-aopAbhängigkeit zusätzlich zum Starter explizit hinzugefügt habe . Wenn Sie mit dem gleichen Problem konfrontiert sind, erklären Sie einfach die Abhängigkeit oder machen Sie sich auf den Weg, es herauszufinden

  • Gibt es einen Versionskonflikt?
  • Warum org.springframework.context.annotation.aspect.*ist das nicht verfügbar
  • Ist Ihre IDE richtig eingerichtet?
  • Usw. usw.
Raf
quelle