Te llevará a comprender a fondo el ciclo de vida de Bean

Resumen: profundizaremos en la parte central de Spring Framework: el ciclo de vida de Spring Bean.

Este artículo lo comparte Huawei Cloud Community " The Road to Spring Master 5: dominar a fondo el ciclo de vida del frijol ", autor: Zhuanyeyang__.

1. Comprender el ciclo de vida del Bean

1.1 Fases del ciclo de vida

En el contenedor Spring IOC, el ciclo de vida de un bean es aproximadamente el siguiente:

  1. Instanciación: al iniciar una aplicación Spring, el contenedor IOC crea una instancia para cada <bean> declarado en el archivo de configuración.
  2. Asignación de atributos: después de la creación de instancias, Spring asigna valores a los atributos de Bean a través del mecanismo de reflexión.
  3. Llamar al método de inicialización: si el bean está configurado con un método de inicialización, Spring lo llamará. El método de inicialización se llama después de que se crea y asigna el Bean.Puede escribir algún código de procesamiento comercial o hacer algún trabajo de inicialización en este método.
  4. Tiempo de ejecución del Bean: En este punto, el Bean está listo para ser utilizado por el programa, ha sido inicializado y asignado.
  5. Cierre de la aplicación: al cerrar el contenedor IOC, Spring procesa el Bean configurado con el método destroy.
  6. Llamar al método de destrucción: si el bean está configurado con el método de destrucción, Spring lo llamará antes de que se hayan utilizado todos los beans y se cierre el contenedor IOC. Puede realizar algún trabajo de liberación de recursos en el método de destrucción, como cerrar la conexión y borrando la caché.

Así es como el contenedor Spring IOC gestiona el ciclo de vida de los beans, nos ayuda a gestionar la creación y destrucción de objetos y hace lo correcto en el momento adecuado.

Podemos llamar a la activación del ciclo de vida una devolución de llamada, porque el método del ciclo de vida lo definimos nosotros mismos, pero la invocación del método la realiza el marco para nosotros, por lo que se puede llamar una "devolución de llamada".

2. Comprender el método init y el método destroy

Comencemos con una de las fases del ciclo de vida más fáciles de entender: los métodos de inicialización y destrucción. Estos métodos pueden funcionar durante las fases de inicialización y destrucción del bean, y demostramos este enfoque a través de ejemplos.

Para facilitar la demostración de XML y los métodos de anotación, a continuación crearemos dos clases para demostrar por separado, a saber, Lion y Elephant, comparemos y observemos paso a paso.

2.1 Crear un Bean desde la configuración XML para ver el ciclo de vida

Primero crea una clase Lion

package com.example.demo.bean;
public class Lion {
 private String name;
 public void setName(String name) {
 this.name = name;
 }
 public void init() {
 System.out.println(name + " has been initialized...");
 }
 public void destroy() {
 System.out.println(name + " has been destroyed...");
 }
}

En XML, usamos la etiqueta <bean> para registrar Lion:

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
 <bean class="com.example.demo.bean.Lion"
 init-method="init" destroy-method="destroy">
 <property name="name" value="simba"/>
 </bean>
</beans>

más el programa principal

package com.example.demo.application;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.support.ClassPathXmlApplicationContext;
@ComponentScan("com.example")
public class DemoApplication {
 public static void main(String[] args) {
 System.out.println("Spring容器初始化开始");
 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
 System.out.println("Spring容器初始化完成。");
 System.out.println("==================");
 System.out.println("Spring容器准备关闭");
 context.close();
 System.out.println("Spring容器已关闭。");
 }
}

resultado de la operación

En la etiqueta <bean>, hay dos atributos: init-method y destroy-method, que se utilizan para especificar los métodos de inicialización y destrucción.

Aquí "simba se ha inicializado...", lo que prueba que se ha llamado al método init(). Cuando se llama a context.close(), consulte "simba ha sido destruido...", lo que prueba que se ha llamado al método destroy().

Antes de inicializar el contenedor IOC, el Bean se ha creado de forma predeterminada y la acción de inicialización se ha completado; cuando el contenedor invoca la acción de destrucción, todos los Beans se destruyen primero y, finalmente, el contenedor IOC se destruye por completo.

Este ejemplo muestra el ciclo de vida del bean Spring a través de una aplicación Spring simple. Podemos usar estos métodos de ciclo de vida según sea necesario mientras creamos el bean.

2.2 Cree un Bean desde la configuración de anotación de clase de configuración para ver el ciclo de vida

Cree otra clase Elefante aquí para comparar con la anterior

package com.example.demo.bean;
public class Elephant {
 private String name;
 public void setName(String name) {
 this.name = name;
 }
 public void init() {
 System.out.println(name + " has been initialized...");
 }
 public void destroy() {
 System.out.println(name + " has been destroyed...");
 }
}

Para las anotaciones, existen atributos similares en las anotaciones @Bean: initMethod y destroyMethod, estos dos atributos tienen la misma función que en la configuración XML.

package com.example.demo.configuration;
import com.example.demo.bean.Elephant;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
@Configuration
@ImportResource("classpath:applicationContext.xml")
public class AnimalConfig {
 @Bean(initMethod = "init", destroyMethod = "destroy")
 public Elephant elephant() {
 Elephant elephant = new Elephant();
 elephant.setName("Dumbo");
 return elephant;
 }
}

Aquí, @ImportResource("classpath:applicationContext.xml") se usa para introducir la configuración xml para crear beans para comparar.

El programa principal se cambia a lo siguiente:

package com.example.demo.application;
import com.example.demo.configuration.AnimalConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan("com.example")
public class DemoApplication {
 public static void main(String[] args) {
 System.out.println("Spring容器初始化开始");
 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AnimalConfig.class);
 System.out.println("Spring容器初始化完成。");
 System.out.println("==================");
 System.out.println("Spring容器准备关闭");
 context.close();
 System.out.println("Spring容器已关闭。");
 }
}

resultado de la operación

Nota: En Spring, si se define un Bean en la configuración de Java y se define un Bean con el mismo id o nombre en el XML, el último Bean registrado anulará el registrado anteriormente, según el orden de carga del archivo de configuración, independientemente de el initMethod o destroyMethod definido en la configuración de Java o la configuración XML, el último efectivo siempre se define en la configuración poscargada.

"init-method" es el término colectivo para los atributos que especifican el método de devolución de llamada de inicialización, ya sea que se use en la configuración XML o en la configuración Java. Asimismo, "destroy-method" es un término colectivo para los atributos que especifican el método de devolución de llamada de destrucción. Más adelante, cuando expliquemos la coexistencia de múltiples ciclos de declaraciones, continuaremos con esta declaración.

2.3 Características de los métodos de inicialización y destrucción

Al configurar los métodos de inicialización y destrucción de Bean en el marco de Spring, debe configurar estos métodos de acuerdo con las especificaciones de Spring; de lo contrario, es posible que Spring no pueda llamarlos correctamente. A continuación se proporciona una explicación y ejemplos para cada característica:

1. Acceso sin restricciones al método: esto significa que Spring puede llamarlo sin importar si el método es público, protegido o privado. Spring invoca estos métodos a través de la reflexión, por lo que puede ignorar las restricciones de acceso de Java. Ejemplo:

public class MyBean {
 private void init() {
 // 初始化代码
 }
}

En el código anterior, incluso si el método init es privado, Spring puede llamarlo normalmente.

2. El método no tiene parámetros: dado que Spring no sabe qué parámetros deben pasarse a estos métodos, estos métodos no pueden tener parámetros. Ejemplo:

public class MyBean {
 public void init() {
 // 初始化代码
 }
}

En el código anterior, el método init no tiene parámetros. Si se agregan parámetros, como public void init (String arg), Spring no podrá llamar a este método.

3. El método no tiene valor de retorno: dado que el valor devuelto no tiene sentido para Spring, estos métodos no deberían tener un valor de retorno. Ejemplo:

public class MyBean {
 public void init() {
 // 初始化代码
 }
}

En el código anterior, el método init es nulo. Si permite que este método devuelva un valor, como public String init(), entonces Spring ignorará este valor devuelto.

4. Los métodos pueden generar excepciones: si se producen errores durante la inicialización o la destrucción, estos métodos pueden generar excepciones para notificar a Spring. Ejemplo:

public class MyBean {
 public void init() throws Exception {
 // 初始化代码
 if (somethingGoesWrong) {
 throw new Exception("Initialization failed.");
 }
 }
}

En el código anterior, si hay un error en el código de inicialización en el método init, generará una excepción. Spring Framework detendrá la creación de beans de forma predeterminada y lanzará una excepción.

2.4 Explorar la secuencia del proceso de inicialización de Bean

En el código anterior, podemos ver que el bean ha sido creado e inicializado en la fase de inicialización del contenedor IOC, entonces, ¿cómo procede la acción de inicialización de cada bean? Modifiquemos Lion para agregar la impresión de la consola al constructor y al método setName, de modo que cuando se llame a estos métodos, reciban comentarios sobre la consola.

package com.example.demo.bean;
public class Lion {
 private String name;
 public Lion() {
 System.out.println("Lion's constructor is called...");
 }
 public void setName(String name) {
 System.out.println("setName method is called...");
 this.name = name;
 }
 public void init() {
 System.out.println(name + " has been initialized...");
 }
 public void destroy() {
 System.out.println(name + " has been destroyed...");
 }
}

Volvemos a ejecutar el programa principal:

@ComponentScan("com.example")
public class DemoApplication {
 public static void main(String[] args) {
 System.out.println("Spring容器初始化开始");
 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
 System.out.println("Spring容器初始化完成。");
 System.out.println("==================");
 System.out.println("Spring容器准备关闭");
 context.close();
 System.out.println("Spring容器已关闭。");
 }
}

resultado de la operación

Podemos sacar una conclusión: en el ciclo de vida del Bean, primero se realiza la asignación de atributos, y luego se ejecuta el método marcado por init-method.

3. @PostConstruct和@PreDestroy

En la especificación JSR250, hay dos anotaciones relacionadas con el ciclo de vida del Bean, a saber, @PostConstruct y @PreDestroy. Estas dos anotaciones corresponden a las fases de inicialización y destrucción del Bean.

El método marcado con la anotación @PostConstruct se llamará después de que se establezcan las propiedades del bean (es decir, se complete la inyección de dependencia), pero antes de que el bean se exponga al mundo exterior (es decir, otros beans pueden hacer referencia a él). Este tiempo se usa generalmente para completar algún trabajo de inicialización.

Se llamará al método marcado con la anotación @PreDestroy antes de que el contenedor Spring destruya el bean, que generalmente se usa para liberar recursos.

3.1 Ejemplo: uso de @PostConstruct y @PreDestroy

Todavía usamos la clase Lion para crear este ejemplo aquí, y modificamos la clase Lion para usar las anotaciones @PostConstruct y @PreDestroy

package com.example.demo.bean;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Component
public class Lion {
 private String name;
 public void setName(String name) {
 this.name = name;
 }
 @PostConstruct
 public void init() {
 System.out.println("Lion is going through init.");
 }
 @PreDestroy
 public void destroy() {
 System.out.println("Lion is going through destroy.");
 }
 @Override
 public String toString() {
 return "Lion{" + "name=" + name + '}';
 }
}

Agregue la anotación @Component a la clase Lion y deje que el contenedor IOC administre esta clase. No agregaremos la clase Elephant aquí para aumentar la dificultad de comprensión.

Los métodos anotados con @PostConstruct y @PreDestroy tienen los mismos requisitos de inicialización y destrucción que los métodos init-method/destroy-method No hay restricciones en los modificadores de acceso y también están disponibles los privados.

Podemos comentar la clase de configuración anterior y la configuración XML, porque no tiene nada que ver con el ejemplo aquí, echemos un vistazo al programa principal:

package com.example.demo.application;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class DemoApplication {
 public static void main(String[] args) {
 System.out.println("Spring容器初始化开始");
 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.example.demo.bean");
 System.out.println("Spring容器初始化完成。");
 System.out.println("==================");
 System.out.println("Spring容器准备关闭");
 context.close();
 System.out.println("Spring容器已关闭。");
 }
}

resultado de la operación

Aquí puede ver que las anotaciones @PostConstruct y @PreDestroy se aplican correctamente durante la inicialización y destrucción de Lion.

3.2 Inicialización y destrucción: comparación de anotación y coexistencia del método init

¿Cómo coexisten las anotaciones @PostConstruct y @PreDestroy con los atributos init-method/destroy-method? vamos a ver

Solo usamos la clase Lion como ejemplo y agregamos nuevos métodos open() y close() a la clase Lion

Todo el código necesario es el siguiente:

león.java

package com.example.demo.bean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class Lion {
 private String name;
 public Lion() {
 System.out.println("Lion构造器");
 }
 public void setName(String name) {
 System.out.println("Lion设置name");
 this.name = name;
 }
 public void open() {
 System.out.println("配置类initMethod - 打开Lion。。。");
 }
 public void close() {
 System.out.println("配置类destroyMethod - 关闭Lion。。。");
 }
 @PostConstruct
 public void init() {
 System.out.println("@PostConstruct - Lion正在进行初始化。。。");
 }
 @PreDestroy
 public void destroy() {
 System.out.println("@PreDestroy - Lion正在进行销毁。。。");
 }
 @Override
 public String toString() {
 return "Lion{" + "name=" + name + '}';
 }
}

Clase de configuración AnimalConfig.java

package com.example.demo.configuration;
import com.example.demo.bean.Lion;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AnimalConfig {
 @Bean(initMethod = "open", destroyMethod = "close")
 public Lion lion() {
 return new Lion();
 }
}

programa principal

package com.example.demo.application;
import com.example.demo.configuration.AnimalConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class DemoApplication {
 public static void main(String[] args) {
 System.out.println("Spring容器初始化开始");
 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AnimalConfig.class);
 System.out.println("Spring容器初始化完成。");
 System.out.println("==================");
 System.out.println("Spring容器准备关闭");
 context.close();
 System.out.println("Spring容器已关闭。");
 }
}

resultado de la operación

Aquí puede ver que las anotaciones @PostConstruct y @PreDestroy siempre tienen mayor prioridad que los atributos initMethod y destroyMethod de la anotación @Bean en la clase de configuración.

4. Implementar las interfaces InitializingBean y AvailableBean

Estas dos interfaces son dos interfaces sobre el ciclo de vida predefinidas por Spring. Se activan al mismo tiempo que el método init/destruir anterior y las anotaciones de la especificación JSR250, y todos se vuelven a llamar durante las fases de inicialización y destrucción del Bean. A continuación se muestra cómo utilizar estas dos interfaces.

4.1 Ejemplo: Implementación de las interfaces InitializingBean y AvailableBean

Para crear un Bean, dejamos que la clase Lion implemente estas dos interfaces:

león.java

package com.example.demo.bean;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
@Component
public class Lion implements InitializingBean, DisposableBean {
 private Integer energy;
 @Override
 public void afterPropertiesSet() throws Exception {
 System.out.println("狮子已经充满能量。。。");
 this.energy = 100;
 }
 @Override
 public void destroy() throws Exception {
 System.out.println("狮子已经消耗完所有能量。。。");
 this.energy = 0;
 }
 @Override
 public String toString() {
 return "Lion{" + "energy=" + energy + '}';
 }
}

La interfaz InitializingBean solo tiene un método: afterPropertiesSet(). En el marco Spring, se llama a este método cuando se han establecido todas las propiedades de un bean. Es decir, una vez que se inicializa el bean, Spring llamará a este método. Podemos hacer una inicialización personalizada después de configurar todas las propiedades del bean.

La interfaz de AvailableBean también tiene un solo método: destroy(). Se llamará a este método cuando el contenedor Spring se apague y destruya el bean. Podemos hacer algo de limpieza antes de que se destruya el frijol.

Programa principal:

package com.example.demo.application;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class DemoApplication {
 public static void main(String[] args) {
 System.out.println("Spring容器初始化开始");
 AnnotationConfigApplicationContext context
 = new AnnotationConfigApplicationContext("com.example.demo.bean");
 System.out.println("Spring容器初始化完成。");
 System.out.println("==================");
 System.out.println("Spring容器准备关闭");
 context.close();
 System.out.println("Spring容器已关闭。");
 }
}

resultado de la operación:

4.2 Coexisten tres ciclos de vida

En el marco de Spring, las tres formas de controlar el ciclo de vida de los frijoles son:

  1. Use el método init y destroy de Spring (métodos personalizados de inicialización y destrucción en la configuración XML o configuración Java);
  2. Use las anotaciones @PostConstruct y @PreDestroy de la especificación JSR-250;
  3. Implemente las interfaces InitializingBean y AvailableBean de Spring.

A continuación, probemos que un Bean define los métodos init-method y destroy-method al mismo tiempo, utiliza las anotaciones @PostConstruct, @PreDestroy e implementa las interfaces InitializingBean y AvailableBean.¿Cuál es el orden de ejecución?

Creamos una nueva clase Lion2 y realizamos el control del ciclo de vida de tres formas al mismo tiempo:

Todo el código que debe ejecutarse es el siguiente:

package com.example.demo.bean;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Component
public class Lion2 implements InitializingBean, DisposableBean {
 private Integer energy;
 public void open() {
 System.out.println("init-method - 狮子开始行动。。。");
 }
 public void close() {
 System.out.println("destroy-method - 狮子结束行动。。。");
 }
 @PostConstruct
 public void gainEnergy() {
 System.out.println("@PostConstruct - 狮子已经充满能量。。。");
 this.energy = 100;
 }
 @PreDestroy
 public void loseEnergy() {
 System.out.println("@PreDestroy - 狮子已经消耗完所有能量。。。");
 this.energy = 0;
 }
 @Override
 public void afterPropertiesSet() throws Exception {
 System.out.println("InitializingBean - 狮子准备行动。。。");
 }
 @Override
 public void destroy() throws Exception {
 System.out.println("DisposableBean - 狮子行动结束。。。");
 }
}

A continuación, registramos Lion2:

package com.example.demo.configuration;
import com.example.demo.bean.Lion2;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AnimalConfig {
 @Bean(initMethod = "open", destroyMethod = "close")
 public Lion2 lion2() {
 return new Lion2();
 }
}

Luego deje que el contenedor IOC de anotación controle esta clase de configuración, el programa principal es el siguiente:

package com.example.demo.application;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class DemoApplication {
 public static void main(String[] args) {
 System.out.println("Spring容器初始化开始");
 AnnotationConfigApplicationContext context
 = new AnnotationConfigApplicationContext("com.example.demo");
 System.out.println("Spring容器初始化完成。");
 System.out.println("==================");
 System.out.println("Spring容器准备关闭");
 context.close();
 System.out.println("Spring容器已关闭。");
 }
}

resultado de la operación:

De los resultados anteriores, podemos sacar las siguientes conclusiones de que el proceso de inicialización y destrucción de un bean de instancia única en el marco Spring tiene tal orden de ejecución:

Secuencia de inicialización: @PostConstruct → InitializingBean → init-method
Secuencia de destrucción: @PreDestroy → AvailableBean → destroy-method

Al inicializar un bean, primero se ejecutará el método de anotación @PostConstruct, luego el método afterPropertiesSet que implementa la interfaz InitializingBean y finalmente el método especificado por init-method.

Al destruir un bean, primero se ejecutará el método de anotación @PreDestroy, luego el método de destrucción que implementa la interfaz del Bean desechable y, finalmente, el método especificado por el método de destrucción.

Combinado con la asignación de atributos (método constructor y método setter) mencionado anteriormente, resuma brevemente el proceso del ciclo de vida de Spring Bean:

  1. Instanciar (a través del método constructor);
  2. Establecer las propiedades del Bean (a través del método setter);
  3. Llame al método de inicialización del Bean (@PostConstruct, al método afterPropertiesSet o al método especificado por init-method);
  4. Bean puede ser utilizado por la aplicación;
  5. Cuando se cierra el contenedor, se llama al método de destrucción del Bean (@PreDestroy, método de destrucción o método especificado por método de destrucción).

5. El ciclo de vida del bean prototipo

El proceso de creación e inicialización de un bean prototipo es similar al de un bean singleton, pero debido a la naturaleza del bean prototipo, su ciclo de vida no es el mismo que el del contenedor IOC.

Aquí está todo el código necesario.

Lion2.java

package com.example.demo.bean;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class Lion2 implements InitializingBean, DisposableBean {
 private Integer energy;
 public void roar() {
 System.out.println("The lion is roaring...");
 }
 public void rest() {
 System.out.println("The lion is resting...");
 }
 @PostConstruct
 public void gainEnergy() {
 System.out.println("@PostConstruct - 狮子已经充满能量。。。");
 this.energy = 100;
 }
 @PreDestroy
 public void loseEnergy() {
 System.out.println("@PreDestroy - 狮子已经消耗完所有能量。。。");
 this.energy = 0;
 }
 @Override
 public void afterPropertiesSet() throws Exception {
 System.out.println("InitializingBean - 狮子准备行动。。。");
 }
 @Override
 public void destroy() throws Exception {
 System.out.println("DisposableBean - 狮子行动结束。。。");
 }
}

Luego declare y configúrelo como un bean prototipo en la configuración de Java de Spring

package com.example.demo.configuration;
import com.example.demo.bean.Lion2;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
@Configuration
public class PrototypeLifecycleConfiguration {
 @Bean(initMethod = "roar", destroyMethod = "rest")
 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
 public Lion2 lion() {
 return new Lion2();
 }
}

Si acabamos de iniciar el contenedor IOC, pero no solicitamos una instancia de Lion2, la inicialización de Lion Bean no ocurrirá de inmediato. En otras palabras, el bean prototipo no se inicializará con el inicio del contenedor IOC. El siguiente es el código que inicia el contenedor pero no solicita el bean:

package com.example.demo.application;
import com.example.demo.configuration.PrototypeLifecycleConfiguration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class DemoApplication {
 public static void main(String[] args) {
 System.out.println("Spring容器初始化开始");
 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
 PrototypeLifecycleConfiguration.class);
 }
}

resultado de la operación:

Cuando solicitamos explícitamente una instancia de Lion2, veremos que todos los métodos de inicialización se ejecutan en un orden predeterminado, que es exactamente el mismo que el de un bean singleton:

package com.example.demo.application;
import com.example.demo.bean.Lion2;
import com.example.demo.configuration.PrototypeLifecycleConfiguration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class DemoApplication {
 public static void main(String[] args) {
 System.out.println("Spring容器初始化开始");
 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
 PrototypeLifecycleConfiguration.class);
 System.out.println("Ready to get a Lion instance...");
 Lion2 lion = context.getBean(Lion2.class);
 System.out.println("A Lion instance has been fetched...");
 System.out.println("Lion instance is no longer needed, preparing to destroy...");
 context.getBeanFactory().destroyBean(lion);
 System.out.println("Lion instance has been destroyed...");
 }
}

resultado de la operación:

Después de comparar los tres ciclos de vida del Bean prototipo y el Bean singleton, se encuentra que cuando se llama al método destroyBean() del contenedor IOC para destruir el Bean prototipo, solo se utiliza el método destroy de la anotación @PreDestroy y la interfaz del Bean Desechable. será activado y marcado por el método de destrucción. El método de destrucción personalizado no se ejecutará.

De aquí podemos concluir que al destruir el prototipo de bean, Spring no ejecutará el método de destrucción personalizado marcado por el método de destrucción, por lo que el método de destrucción del prototipo de bean también tiene limitaciones. Si hay una lógica de limpieza importante que debe ejecutarse cuando se destruye el Bean, entonces esta parte de la lógica debe colocarse en el método anotado @PreDestroy o en el método de destrucción de la interfaz del Bean desechable.

6. Resumen de tres formas de controlar el ciclo de vida del Bean en Spring

 

Haga clic para seguir y conocer las nuevas tecnologías de Huawei Cloud por primera vez~

{{o.nombre}}
{{m.nombre}}

Supongo que te gusta

Origin my.oschina.net/u/4526289/blog/10083868
Recomendado
Clasificación