Quando l’IoC container di Spring istanzia un nuovo bean, esso potrebbe aver bisogno di essere inizializzato per assumere uno stato consistente prima di poter essere utilizzato. Analogamente quando il bean è rimosso dal container potrebbe essere necessario eseguire una operazione di clean up. Di seguito sono descritti i tre possibili approcci che Spring mette a disposizione per gestire il ciclo di vita di un bean.
File di Configurazione
Nel caso in cui il bean è configurato attraverso file xml è possibile utilizzare gli attributi init-method
e desptroy-method
del tag bean
. Ad esempio con la seguente definizione:
1 2 3 4 |
<bean id="beanLifecycle" class="it.inspiredsoft.BeanLifecycle" init-method="init" destroy-method="cleanup"/> |
i metodo init()
e cleanup()
sono dichiarati rispettivamente come metodo di inizializzazione e pulizia. Entrambe non devono avere parametri formali nella loro definizione.
1 2 3 4 5 6 7 8 |
public class BeanLifecycle { public void init() { System.out.println( "INIT" ); } public void cleanup() { System.out.println( "DESTROY" ); } } |
Il principale svantaggio di tale approccio è che dalla semplice ispezione del codice non è possibile intuire la finalità dei due metodi.
E’ anche possibile definire dei metodi di default di inizializzazione e clean up validi per tutti i bean dichiarandoli direttamente negli attributi default-init-method
e default-destroy-method
del del tag beans
come segue:
1 2 3 |
<beans default-init-method="init" default-destroy-method="destroy"> ... </beans> |
Implementazione di Interfacce
Un’altra possibilità offerta da Spring è quella di estendere le interfacce InitializingBean
e DisposableBean
. La prima specifica un solo metodo che è invocato dal container a seguito di creazione del bean:
1 |
void afterPropertiesSet() throws Exception; |
Analogamente il secondo specifica un metodo che è invocato quando il bean è rimosso dal container:
1 |
void destroy() throws Exception; |
1 2 3 4 5 6 7 8 9 |
@Component public class BeanLifecycle implements InitializingBean, DisposableBean { public void destroy() throws Exception { System.out.println( "DESTROY" ); } public void afterPropertiesSet() throws Exception { System.out.println( "INIT" ); } } |
Specifica JSR-250
Tale specifica ha l’obiettivo di definire un insieme di annotazioni, che definiscono concetti semantici comuni ed utilizzabili nei componenti Java EE e Java SE, al fine di evitare ridondanze. In particolare Spring supporta le annotazioni @PostConstruct
e @PreDestroy
. Il bean apparirà quindi come segue:
1 2 3 4 5 6 7 8 9 10 11 |
@Component public class BeanLifecycle { @PreDestroy public void destroy() throws Exception { System.out.println( "DESCTORY" ); } @PostConstruct public void afterPropertiesSet() throws Exception { System.out.println( "INIT" ); } } |
Tale approccio rende chiaro l’utilizzo dei metodi ma richiede l’attivazione del component scanning. Inoltre decentralizza la configurazione dei bean.
Per l’utilizzo delle annotazioni definite in JSR-250 è necessario scaricare le API della implementazione di riferimento o più semplicemente inserire la dipendenza nel file pom.xml
di Maven:
1 2 3 4 5 |
<dependency> <groupId>javax.annotation</groupId> <artifactId>jsr250-api</artifactId> <version>1.0</version> </dependency> |
Combinazione degli Approcci
Se molteplici meccanismi per la gestione del ciclo di vita sono configurati per un bean, e ognuno fa riferimento ad un diverso metodo, ogni metodo è eseguito nell’ordine indicato di seguito. Tuttavia, se lo stesso metodo è configurato per più di uno di questi meccanismi, tale metodo viene eseguita una sola volta.
L’ordine di invocazione dei metodi per l’inizializzazione dei bean sono:
- Metodi annotati con
@PostConstruct
; - Il metodo
afterPropertiesSet()
dell’interfacciaInitializingBean
; - Il metodo custom
init()
dichiarato nell’XML.
Analogamente, l’ordine di invocazione dei metodi per il clean up dei bean sono:
- Metodi annotati con
@PreDestroy
; - Il metodo
destroy()
dell’interfacciaDisposableBean
; - Il metodo custom
destroy()
dichiarato nell’XML.
Chiusura del Contesto
Se nel fare la sperimentazioni non viene stampato il messaggio di destroy significa che non è stato chiuso il contesto di Spring. Per farlo deve essere fatto il downcast dell’ApplicationContext
di Spring a ConfigurableApplicationContext
che dispone del metodo close()
:
1 |
( (ConfigurableApplicationContext) context ).close(); |