Capire getBean () in primavera

1. Introduzione

In questo tutorial, esamineremo diverse varianti del metodo BeanFactory.getBean () .

In poche parole, come suggerisce anche il nome del metodo, questo è responsabile del recupero di un'istanza di bean dal contenitore Spring .

2. Installazione di fagioli primaverili

Per prima cosa, definiamo alcuni bean Spring per i test. Esistono diversi modi in cui possiamo fornire definizioni di bean per il contenitore Spring, ma nel nostro esempio utilizzeremo la configurazione Java basata su annotazioni:

@Configuration class AnnotationConfig { @Bean(name = {"tiger", "kitty"}) @Scope(value = "prototype") Tiger getTiger(String name) { return new Tiger(name); } @Bean(name = "lion") Lion getLion() { return new Lion("Hardcoded lion name"); } interface Animal {} } 

Abbiamo creato due fagioli. Lion ha l'ambito singleton predefinito. Tiger è impostato esplicitamente sull'ambito del prototipo. Inoltre, tieni presente che abbiamo definito nomi per ogni bean che useremo in ulteriori richieste.

3. Le API getBean ()

BeanFactory fornisce cinque diverse firme del metodo getBean () che esamineremo nelle seguenti sottosezioni.

3.1. Recupero del fagiolo per nome

Vediamo come possiamo recuperare un'istanza di bean Lion usando il suo nome:

Object lion = context.getBean("lion"); assertEquals(Lion.class, lion.getClass());

In questa variante, forniamo un nome e, in cambio, otteniamo un'istanza della classe Object se esiste un bean con il nome specificato nel contesto dell'applicazione. Altrimenti, sia questa che tutte le altre implementazioni generano NoSuchBeanDefinitionException se la ricerca del bean fallisce.

Lo svantaggio principale è che dopo aver recuperato il bean, dobbiamo lanciarlo nel tipo desiderato. Ciò può produrre un'altra eccezione se il bean restituito ha un tipo diverso da quello previsto .

Supponiamo di provare a ottenere una tigre usando il nome "leone". Quando eseguiamo il cast del risultato su Tiger , verrà generata un'eccezione ClassCastException :

assertThrows(ClassCastException.class, () -> { Tiger tiger = (Tiger) context.getBean("lion"); });

3.2. Recupero del fagiolo per nome e tipo

Qui dobbiamo specificare sia il nome che il tipo del bean richiesto:

Lion lion = context.getBean("lion", Lion.class);

Rispetto al metodo precedente, questo è più sicuro perché otteniamo immediatamente le informazioni sulla mancata corrispondenza del tipo:

assertThrows(BeanNotOfRequiredTypeException.class, () -> context.getBean("lion", Tiger.class)); }

3.3. Recupero del fagiolo per tipo

Con la terza variante di getBean (), è sufficiente specificare solo il tipo di bean:

Lion lion = context.getBean(Lion.class);

In questo caso, dobbiamo prestare particolare attenzione a un risultato potenzialmente ambiguo :

assertThrows(NoUniqueBeanDefinitionException.class, () -> context.getBean(Animal.class)); }

Nell'esempio sopra, poiché sia Lion che Tiger implementano l' interfaccia Animal , la semplice specifica del tipo non è sufficiente per determinare in modo univoco il risultato. Pertanto, otteniamo un'eccezione NoUniqueBeanDefinitionException .

3.4. Recupero del bean in base al nome con i parametri del costruttore

Oltre al nome del bean, possiamo anche passare i parametri del costruttore:

Tiger tiger = (Tiger) context.getBean("tiger", "Siberian");

Questo metodo è leggermente diverso perché si applica solo ai bean con ambito prototipo .

Nel caso dei singleton, otterremo una BeanDefinitionStoreException.

Poiché un prototipo di bean restituirà un'istanza appena creata ogni volta che viene richiesta dal contenitore dell'applicazione, possiamo fornire i parametri del costruttore al volo quando si richiama getBean () :

Tiger tiger = (Tiger) context.getBean("tiger", "Siberian"); Tiger secondTiger = (Tiger) context.getBean("tiger", "Striped"); assertEquals("Siberian", tiger.getName()); assertEquals("Striped", secondTiger.getName());

Come possiamo vedere, ogni Tiger riceve un nome diverso in base a quello che abbiamo specificato come secondo parametro durante la richiesta del bean.

3.5. Recupero del bean in base al tipo con i parametri del costruttore

Questo metodo è analogo all'ultimo, ma dobbiamo passare il tipo invece del nome come primo argomento:

Tiger tiger = context.getBean(Tiger.class, "Shere Khan"); assertEquals("Shere Khan", tiger.getName());

Simile al recupero di un bean in base al nome con i parametri del costruttore, questo metodo si applica solo ai bean con ambito prototipo .

4. Considerazioni sull'utilizzo

Nonostante sia definito nell'interfaccia BeanFactory , il metodo getBean () è più frequentemente accessibile tramite ApplicationContext. In genere, non vogliamo utilizzare il metodo getBean () direttamente nel nostro programma .

I fagioli dovrebbero essere gestiti dal contenitore. Se vogliamo usarne uno, dovremmo fare affidamento sull'inserimento delle dipendenze piuttosto che su una chiamata diretta ad ApplicationContext.getBean () . In questo modo, possiamo evitare di mescolare la logica dell'applicazione con i dettagli relativi al framework.

5. conclusione

In questo breve tutorial, abbiamo esaminato tutte le implementazioni del metodo getBean () dall'interfaccia BeanFactory e abbiamo descritto i pro ei contro di ciascuna.

Tutti gli esempi di codice mostrati qui sono disponibili su GitHub.