Jak w Spring wstrzyknąć zależności do utworzonego samodzielnie obiektu?


128

Powiedzmy, że mamy klasę:

public class MyClass {
    @Autowired private AnotherBean anotherBean;
}

Następnie stworzyliśmy obiekt tej klasy (lub inny framework stworzył instancję tej klasy).

MyClass obj = new MyClass();

Czy nadal można wstrzykiwać zależności? Coś jak:

applicationContext.injectDependencies(obj);

(Myślę, że Google Guice ma coś takiego)

Odpowiedzi:


194

Możesz to zrobić za pomocą autowireBean()metody AutowireCapableBeanFactory. Przekażesz mu dowolny obiekt, a Spring potraktuje go jak coś, co sam stworzył, i zastosuje różne elementy i elementy automatycznego okablowania.

Aby zdobyć AutowireCapableBeanFactory, po prostu autowire, że:

private @Autowired AutowireCapableBeanFactory beanFactory;

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

Dobra odpowiedź (+1). Istnieje również druga metoda, dzięki której możesz wpłynąć na to, jak przebiega automatyczne okablowanie
Sean Patrick Floyd

Ale co jeśli mam dwa obiekty, a drugi autodrut. Jak fabryka fasoli autowire radzi sobie z zależnościami w przypadku?
Vadim Kirilchuk

3
To właściwie zły wzór. Jeśli tak naprawdę używasz MyBean, dlaczego nie mieć po prostu konstruktora z AnotherBean jako parametrem. Coś jak: codeprivate @Autowired AnotherBean bean; public void doStuff () {MyBean obj = new MyBean (bean); } code. Wygląda na to, że z tymi wszystkimi adnotacjami ludzie są naprawdę zdezorientowani i po prostu nie używają podstawowego wzorca, który był w pakiecie java SDK od pierwszego dnia :(
Denis

3
Zgadzam się - Wiosna na nowo zdefiniowała cały język. Teraz używamy interfejsów jako konkretnych klas, metod jako instancji klas i wszelkiego rodzaju skomplikowanych i ciężkich metod kodowania, aby robić to, co robiłeś z nowym i przyzwoitym projektem.
Rodney P. Barbati

@Denis, jeśli MyBean ma zależności, których rzeczywista klasa nie potrzebuje, rejestrujesz zależności, które w rzeczywistości nie istnieją, tylko w celu wystąpienia klasy, więc tak naprawdę nie ma różnicy.
Dalton,

17

Możesz również oznaczyć swoją MyClass adnotacją @Configurable:

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

Następnie w czasie tworzenia automatycznie wstrzyknie swoje zależności. Powinieneś także mieć <context:spring-configured/>w kontekście swojej aplikacji xml.


2
Galz666, twoja metoda wygląda na znacznie czystszą, jak na to, co chcę zrobić. Jednak nie mogę zmusić go do pracy. Nie mam pliku xml i używam w całości konfiguracji Java. Czy istnieje odpowiednik <context:spring-configured/>?
masstroy

1
To czyste rozwiązanie, ale wymaga trochę więcej wysiłku: należy albo użyć tkania w czasie ładowania, jak pokazuje iimuhin powyżej, lub dodać kompilator AspectJ do projektu. Czas ładowania, jak sugeruje nazwa, spowoduje dodatkowe koszty w czasie wykonywania.
jsosnowski

4

Właśnie dostałem tę samą potrzebę iw moim przypadku była to już logika wewnątrz nieobsługiwanej przez Spring klasy javy, do której miał dostęp ApplicationContext. Zainspirowany scaffmanem. Rozwiązane przez:

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

3

Chciałem udostępnić moje rozwiązanie, które jest zgodne z @Configurablepodejściem brieflywspomnianym w odpowiedzi @ glaz666, ponieważ

  • Odpowiedź przez @skaffman ma prawie 10 lat, a to nie znaczy, nie wystarczająco dobre lub nie działa
  • Odpowiedź @ glaz666 jest krótka i nie pomogła mi w rozwiązaniu problemu, ale wskazała mi właściwy kierunek

Moja konfiguracja

  1. Spring Boot 2.0.3 z Spring Neo4j & Aop starts(co i tak nie ma znaczenia)
  2. Utwórz instancję fasoli, gdy Spring Bootjest gotowa, używając @Configurablepodejścia (używając ApplicationRunner)
  3. Gradle i Eclipse

Kroki

Musiałem wykonać poniższe kroki, aby to działało

  1. Do @Configurable(preConstruction = true, autowire = Autowire.BY_TYPE, dependencyCheck = false)umieszczenia na wierzchu, Beanktóry ma zostać utworzony ręcznie. W moim przypadku Beaninstancja, która ma być ręcznie @Autowiredutworzona, ma usługi, stąd rekwizyty do powyższej adnotacji.
  2. Dodaj adnotację do XXXApplicaiton.javapliku głównego Spring Boot (lub pliku z adnotacją @SpringBootApplication) z @EnableSpringConfiguredi@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.ENABLED)
  3. Dodaj zależności w pliku kompilacji (np. Build.gradle lub pom.xml w zależności od tego, którego używasz) compile('org.springframework.boot:spring-boot-starter-aop')icompile('org.springframework:spring-aspects:5.0.7.RELEASE')
  4. Nowe + to, Beanktóre jest opatrzone adnotacją w @Configurabledowolnym miejscu, a jego zależności powinny być automatycznie przypisane.

* W odniesieniu do punktu # 3 powyżej, zdaję sobie sprawę, że org.springframework.boot:spring-boot-starter-aopprzejściowo wyciąga spring-aop(jak pokazano tutaj mavencentral ), ale w moim przypadku Eclipse nie rozwiązało @EnableSpringConfiguredadnotacji, dlatego też wyraźnie dodałem spring-aopzależność oprócz startera. Jeśli napotkasz ten sam problem, po prostu zadeklaruj zależność lub udaj się na przygodę z rozwiązywaniem problemów

  • Czy istnieje konflikt wersji?
  • Dlaczego org.springframework.context.annotation.aspect.*nie jest dostępny
  • Czy twoje IDE jest poprawnie skonfigurowane
  • Itd itd.
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.