Wywołanie metody z adnotacjami @Bean w konfiguracji Spring Java

102

Jestem ciekawy, jak wtrysk sprężyny obsługuje wywoływanie metod z @Beanadnotacją. Jeśli umieszczę @Beanadnotację w metodzie i zwrócę instancję, rozumiem, że to mówi spring o utworzeniu fasoli przez wywołanie metody i pobranie zwróconej instancji. Jednak czasami ta fasola musi być używana do łączenia innych ziaren lub ustawiania innego kodu. Zwykłym sposobem jest to wywołanie @Beanmetody z adnotacjami w celu pobrania instancji. Moje pytanie brzmi: dlaczego nie powoduje to unoszenia się wielu egzemplarzy fasoli?

Na przykład zobacz poniższy kod (zaczerpnięty z innego pytania). entryPoint()Metoda jest opatrzone @Bean, tak to sobie wyobrazić, wiosna będzie utworzyć nową instancję BasicAuthenticationEntryPointjako fasoli. Następnie entryPoint()ponownie wywołujemy w bloku konfiguracji, ale wygląda na to, że entryPoint()zwraca instancję bean i nie jest wywoływana wiele razy (próbowałem rejestrować i otrzymałem tylko jeden wpis w dzienniku). Potencjalnie moglibyśmy wywołać entryPoint()wiele razy w innych częściach konfiguracji i zawsze otrzymalibyśmy tę samą instancję. Czy moje rozumienie tego jest prawidłowe? Czy wiosna w jakiś magiczny sposób przepisuje metody z adnotacjami @Bean?

@Bean
public BasicAuthenticationEntryPoint entryPoint() {
    BasicAuthenticationEntryPoint basicAuthEntryPoint = new BasicAuthenticationEntryPoint();
    basicAuthEntryPoint.setRealmName("My Realm");
    return basicAuthEntryPoint;
}

@Override
protected void configure(HttpSecurity http) throws Exception {

    http
        .exceptionHandling()
            .authenticationEntryPoint(entryPoint())
            .and()
        .authorizeUrls()
            .anyRequest().authenticated()
            .and()
        .httpBasic();       
}
markwatson
źródło

Odpowiedzi:

134

Tak, wiosna robi trochę magii . Sprawdź Spring Docs :

Tutaj pojawia się magia: wszystkie @Configurationklasy są podklasy w czasie uruchamiania za pomocą CGLIB . W podklasie metoda podrzędna najpierw sprawdza kontener pod kątem zbuforowanych (w określonym zakresie) bean, zanim wywoła metodę nadrzędną i utworzy nową instancję.

Oznacza to, że wywołania @Beanmetod są przekazywane przez CGLIB i dlatego zwracana jest buforowana wersja komponentu bean (nowa nie jest tworzona).

Domyślny zakres @Beans to SINGLETON, jeśli określisz inny zakres, na przykład PROTOTYPEwywołanie zostanie przekazane do oryginalnej metody.

Należy pamiętać, że nie dotyczy to metod statycznych . Zgodnie z dokumentami wiosennymi:

Wywołania @Beanmetod statycznych nigdy nie są przechwytywane przez kontener, nawet w obrębie @Configurationklas (jak opisano wcześniej w tej sekcji), ze względu na ograniczenia techniczne: Podklasy CGLIB mogą przesłonić tylko metody niestatyczne. W konsekwencji bezpośrednie wywołanie innej @Beanmetody ma standardową semantykę języka Java, co powoduje, że niezależne wystąpienie jest zwracane bezpośrednio z samej metody fabrycznej.

wassgren
źródło
Czy można zastąpić ziarna utworzone w ten sposób? Na przykład mam klasę zdefiniowaną przez Spring, która bezpośrednio wywołuje metodę tworzenia fasoli. Chcę, żeby nie używano fasoli stworzonej tą metodą, ale taką, którą sam definiuję (dodając do niej adnotacje @Beani @Primary).
Fons
4
Ale przypominam sobie również, że proxy (jdk lub CGLIB, w zależności od tego) nie może działać w trybie auto-wywołania, więc w jaki sposób @Configuration definiuje zależność między fasolami? Używa dokładnie samo-inwokacji
Nowhy
3
@Nowhy CGLib allows us to create proxy classes at runtime by creating sub class of specified class using Byte code generation. CGLib proxies are used in the case where Proxy is to be created for those class which does not have any interfaces or have methods which are not declared in the implementing interface. W tym przypadku CGLIB tworzy podklasę klasy @Configuration i przesłania jej metody (w tym metodę @Bean). Tak więc, gdy wywołujemy metodę @Bean z innej metody, w rzeczywistości wywołujemy jej nadpisaną wersję (dzięki dynamicznemu wiązaniu java).
Flame239,
Czy samoInvocation AOP w @Componentbędzie działał, jeśli używam CHLIB do tworzenia serwerów proxy zamiast java Poxy?
Antoniossss