2014-04-17 12 views
6

Ho dichiarato due bean dello stesso tipo di classe. Inizializzati come @Lazy. @Autowiring un bean di essi inizializzava automaticamente anche l'altro bean. Sono stato sorpreso di vedere quel comportamento. Solo curioso di sapere di più sul meccanismo.Caricamento lazy primaverile - caricamento di un bean su tutti i bean @Lazy di quella classe

Codice

//bean 
public class HelloWorld { 
    public HelloWorld(String msg){ 
     System.out.println(msg + ", " + this); 
    } 
} 

@Configuration 
@Lazy 
public class SpringAppContext { 

    @Bean(name="helloworld1") 
    public HelloWorld helloworld1(){ 
     return new HelloWorld("helloworld1"); 
    } 
    @Bean(name="helloworld2") 
    public HelloWorld helloworld2(){ 
     return new HelloWorld("helloworld2"); 
    } 
} 

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(classes={SpringAppContext.class}) 
public class SpringBeanLazyLoadTest { 
    @Autowired 
    private HelloWorld helloworld2; 

    @Test // this test is lame but just trying out. 
    public void print(){ 
     System.out.println("Autowired: " + helloworld2); 
    } 
} 

uscita

helloworld2, [email protected] 
helloworld1, [email protected] // why was helloworld1 initialized? 
Autowired: [email protected] 

Se si osserva l'uscita, si può notare che il fagiolo helloworld1 viene inizializzato quando helloworld2 è @Autowired.

Ho provato rimuovendo @Autowired e ha prodotto risultati attesi: nessuno dei fagioli inizializzato.

+0

mi sarei aspettato il test a fallire. '@ Autowired' esegue l'iniezione per tipo e non per nome. Quindi, data la natura 'byType', tutti i bean di quel tipo verranno istanziati. Tuttavia, dato che hai un solo campo '@ Autowired', mi sarei aspettato che fallisse con un messaggio che ti diceva che si aspettava 1 bean ma 2. –

risposta

9

Quando si utilizza @Autowired direttamente, il metodo di iniezione è byType. In altre parole, il contenitore vede

@Autowired 
private HelloWorld helloworld2; 

e cerca di trovare un fagiolo di tipo HelloWorld nel ApplicationContext per iniettare.

Il processo di risoluzione del bean da iniettare consiste nell'ottenere tutti i bean candidati che consiste nella creazione dei bean. Quindi i chicchi che sono @Lazy non cambiano nulla. Dovranno ancora essere creati per essere iniettati.

Per chiarire il commento M. Deinum's sulla domanda, hai fornito i nomi dei fagioli. Ad esempio,

@Bean(name="helloworld1") 

Quando si esegue il processo di iniezione, Spring trova tutti i fagioli candidati che possono essere iniettati. Se ce n'è più di uno, filtrerà attraverso di loro e cercherà di trovare il miglior candidato. Se non è possibile, genererà eccezioni. Uno dei passaggi per trovare un candidato migliore è confrontare il nome del bean con il nome del campo obiettivo. Dalla tua corrispondenza, verrà scelto il bean denominato helloworld2.

Rimuovendo @Autowired, i bean non vengono mai richiesti dallo ApplicationContext e quindi mai inizializzati.

2

Dalla primavera docs

Tuttavia, quando un fagiolo pigro-inizializzato è una dipendenza di un Singleton di fagioli che non è pigro-inizializzato, l'ApplicationContext crea il fagiolo pigro-inizializzato all'avvio, perché deve soddisfare le dipendenze del singleton . Il bean con inizializzazione lazy viene iniettato in un bean singleton altrove che non è inizializzato in modo pigro.

Nel tuo caso di test, il fagiolo pigro è avidamente inizializzato come il comportamento predefinito di impianto di prova primavera è quello di preparare l'istanza della classe di prova completamente (iniettando tutte le dipendenze con entusiasmo) per poi consegnarla a JUnit. Il luogo esatto dove avviene è DependencyInjectionTestExecutionListener

protected void injectDependencies(final TestContext testContext) throws Exception { 
     Object bean = testContext.getTestInstance(); 
     AutowireCapableBeanFactory beanFactory = testContext.getApplicationContext().getAutowireCapableBeanFactory(); 
     beanFactory.autowireBeanProperties(bean, AutowireCapableBeanFactory.AUTOWIRE_NO, false); 
     beanFactory.initializeBean(bean, testContext.getTestClass().getName()); 
     testContext.removeAttribute(REINJECT_DEPENDENCIES_ATTRIBUTE); 
    } 
1

Vecchio post ma ancora.Ora si può fare:

@Bean(name="helloworld1", autowire=Autowire.BY_NAME) 
public HelloWorld helloworld1(){ 
    return new HelloWorld("helloworld1"); 
} 
@Bean(name="helloworld2", autowire=Autowire.BY_NAME) 
public HelloWorld helloworld2(){ 
    return new HelloWorld("helloworld2"); 
} 

E/o @Qualifier:

@Autowired 
@Qualifier("helloworld2") 
private HelloWorld hello; 
Problemi correlati