Desmitificando el ciclo de vida del framework Spring y la explicación detallada del singleton [preguntas de la entrevista con respuestas súper detalladas]

Tabla de contenido

I. Introducción

1.1 Introducir el concepto de Spring framework y Bean

En segundo lugar, la fase de creación de instancias de Bean

2.1.Proceso de creación de instancias de bean

2.2 Introducir el uso de constructores predeterminados y métodos de fábrica

3. Fase de inicialización del Bean

3.1 Uso de la interfaz InitializingBean y la anotación @PostConstruct

3.2.Configuración del método de inicialización del bean y secuencia de ejecución

Cuarto, la etapa de destrucción de Bean

4.1 Uso de la interfaz de DisabledBean y la anotación @PreDestroy

4.2.Configuración del método de destrucción de beans y orden de ejecución

5. Explicación de las preguntas de la entrevista

5.1.Ciclo de vida del frijol

en conclusión:

5.2 ¿El JavaBean en Spring es una instancia única o múltiple?

Argumento:

5.3 ¿Cuándo se crean JavaBean de instancia única y JavaBean de múltiples instancias?

Argumento:

5.4 ¿Inicializaremos JavaBean cuando usemos un singleton?

Argumento:


I. Introducción

1.1 Introducir el concepto de Spring framework y Bean

¡Hola amigos! Permítame analizar la historia de Spring Framework y Bean para usted.

El framework Spring es como un santo patrón, se hace cargo de la gestión de las aplicaciones Java. Es una especie de súper organizador de fiestas, que le permite administrar y controlar fácilmente sus aplicaciones. Su objetivo es proporcionar una forma eficiente y flexible de crear aplicaciones empresariales.

Entonces, ¿qué es Bean? Los frijoles son en realidad objetos reales en el marco de Spring. ¡Puedes pensar en Bean como pequeños amigos, divirtiéndose en la fiesta de Spring Framework! Cada Bean tiene su propio ciclo de vida, al igual que los seres humanos tienen etapas de nacimiento, crecimiento, trabajo y jubilación.

En primer lugar, la creación de instancias de Bean es como nuestro nacimiento, Spring es responsable de crear objetos Bean y cargarlos en el contenedor. Luego, la asignación de atributos de Bean es como si aprendiésemos nuevas habilidades en el proceso de crecimiento, se les inyectan varios atributos y se vuelven coloridos.

A continuación, está la fase de inicialización del Bean. Al igual que debemos prepararnos antes de comenzar a trabajar, Bean también puede realizar algunas operaciones de inicialización, incluida la llamada a métodos de inicialización específicos, o realizar algún trabajo posterior a través del posprocesador de Bean.

Finalmente, cuando la aplicación ya no necesita un Bean, puede realizar algunas operaciones de destrucción, como liberar recursos, cerrar conexiones a bases de datos, etc., tal como lo retiramos.

En resumen, Spring Framework y Bean son como fiestas en las que estos pequeños amigos van y vienen en varias etapas, trayendo alegría y logros. Sin embargo, no se preocupe, Spring Framework es un organizador de fiestas responsable y se asegurará de que cada frijol se administre y cuide adecuadamente.

¡Espero que esta introducción humorística le brinde una mejor comprensión del marco de Spring y los beans!

En segundo lugar, la fase de creación de instancias de Bean

2.1.Proceso de creación de instancias de bean

El proceso de creación de instancias de Bean se refiere al proceso de convertir el Bean definido en una instancia de objeto disponible. En el marco de Spring, la creación de instancias de Bean se puede dividir en las siguientes etapas:

  1. Cargando definición de Bean: use archivos de configuración (como archivos de configuración XML) o anotaciones para cargar definiciones de Bean en el contenedor, y Spring Framework es responsable del análisis.

  2. Instanciar Bean: Crea una instancia de Bean en la memoria de acuerdo con la definición y la información de configuración del Bean. Esto se puede hacer a través de la creación de instancias del constructor, la creación de instancias del método de fábrica o mediante la reflexión de objetos, etc.

  3. Asignación de atributos: asigne atributos a objetos Bean instanciados, incluidos tipos de datos básicos, tipos de referencia y tipos de colección. Los atributos se pueden inyectar en dependencias a través de anotaciones o archivos de configuración XML.

  4. Devolución de llamada de la interfaz Aware: si Bean implementa la interfaz Aware, Spring detectará y llamará automáticamente al método de devolución de llamada correspondiente, por ejemplo, la interfaz ApplicationContextAware puede obtener el objeto ApplicationContext.

  5. Método de inicialización personalizado: si el bean está configurado con un método de inicialización (puede ser a través de anotaciones o archivos de configuración XML), Spring llamará a este método para realizar algunas operaciones de inicialización personalizadas después de que el bean complete la asignación de propiedades.

  6. Llamada al método de posprocesador: si se configura un posprocesador de Bean (BeanPostProcessor), Spring detectará y llamará automáticamente a sus métodos relacionados para operaciones de procesamiento adicionales.

  7. Bean está listo: después de los pasos anteriores, el proceso de creación de instancias de Bean se completa y el contenedor puede administrarlo y usarlo.

2.2 Introducir el uso de constructores predeterminados y métodos de fábrica

Constructor predeterminado : el constructor predeterminado es un constructor sin argumentos, que no pasa ningún parámetro al proceso de creación de objetos. Spring llamará automáticamente al constructor predeterminado para instanciar el objeto Bean. Este método es ampliamente utilizado y es conveniente para crear objetos sin pasar parámetros de otras formas. Por ejemplo:

public class MyBean {
    // 默认构造函数
    public MyBean() {
        // 初始化操作
    }
}

Método de fábrica : un método de fábrica es una forma de instanciar un objeto Bean a través de un método especial. Normalmente, este método se define en una clase de fábrica dedicada. A través del método de fábrica, podemos tener más flexibilidad para crear objetos Bean y podemos personalizar operaciones como pasar parámetros. Por ejemplo:

public class MyBeanFactory {
    // 工厂方法
    public static MyBean createMyBean() {
        // 创建Bean对象的逻辑
        return new MyBean();
    }
}

Código de muestra: muestra cómo usar el constructor predeterminado y el método de fábrica para instanciar un objeto Bean:

public class MyBean {
    private String message;

    // 默认构造函数
    public MyBean() {
        this.message = "Hello, world!";
    }

    // getter和setter方法

    public static MyBean createMyBean() {
        MyBean myBean = new MyBean();
        myBean.setMessage("Hello, Spring!");
        return myBean;
    }
}

3. Fase de inicialización del Bean

3.1 Uso de la interfaz InitializingBean y la anotación @PostConstruct

La interfaz InitializingBean utiliza

Esta interfaz define un método afterPropertiesSet() Cuando se establecen todas las propiedades del Bean, el contenedor Spring llamará automáticamente a este método para completar la operación de inicialización.

import org.springframework.beans.factory.InitializingBean;

public class MyBean implements InitializingBean {
    private String message;
    
    public void setMessage(String message) {
        this.message = message;
    }
    
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean: Bean is being initialized with message: " + message);
    }
}

Uso de la anotación @PostConstruct

Esta anotación está marcada en el método de inicialización del Bean, lo que indica que el método se ejecutará automáticamente después de que se establezcan las propiedades del Bean para completar la operación de inicialización del Bean.

import javax.annotation.PostConstruct;

public class MyBean {
    private String message;
    
    public void setMessage(String message) {
        this.message = message;
    }
    
    @PostConstruct
    public void init() {
        System.out.println("@PostConstruct: Bean is being initialized with message: " + message);
    }
}

Cabe señalar que la interfaz InitializingBean y la anotación @PostConstruct se pueden usar al mismo tiempo, pero estos dos métodos no son necesarios, puede elegir uno de ellos para inicializar el Bean según sus necesidades.

En Spring, también puede especificar el método de inicialización de Bean a través del archivo de configuración y usar el atributo init-method de la etiqueta <bean> en el archivo de configuración XML para configurarlo. Los ejemplos son los siguientes:

<bean id="myBean" class="com.example.MyBean" init-method="init">
    <property name="message" value="Hello World" />
</bean>

3.2.Configuración del método de inicialización del bean y secuencia de ejecución

Ya sea que usen la interfaz InitializingBean, la anotación @PostConstruct o el archivo de configuración XML, se pueden usar para especificar el método de inicialización de Bean, y el orden de ejecución es el mismo: primero ejecute la inyección de dependencia del atributo y luego ejecute el método de inicialización.

public class Example {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        
        MyBean bean = context.getBean(MyBean.class);
        // Bean已经被初始化完成并且可以使用
        
        ((ConfigurableApplicationContext) context).close();
    }
}

En el ejemplo anterior, se crea un objeto ApplicationContext y se carga un archivo de configuración XML. Al llamar al método getBean() para obtener una instancia de MyBean, el contenedor Spring realizará automáticamente operaciones de inyección e inicialización de propiedades. Cuando cerramos la aplicación, podemos llamar al método ((ConfigurableApplicationContext) context).close() para cerrar el contenedor.

Cuarto, la etapa de destrucción de Bean

4.1 Uso de la interfaz de DisabledBean y la anotación @PreDestroy

La interfaz de DisabledBean utiliza

Esta interfaz define un método destroy (). Cuando el Bean necesita ser destruido, el contenedor Spring llamará automáticamente a este método para completar el trabajo de limpieza. Los ejemplos son los siguientes:

import org.springframework.beans.factory.DisposableBean;

public class MyBean implements DisposableBean {
    private String message;
    
    public void setMessage(String message) {
        this.message = message;
    }
    
    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean: Bean is being destroyed with message: " + message);
    }
}

Uso de la anotación @PreDestroy

Esta anotación está marcada en el método de destrucción del bean, lo que indica que el método se ejecutará automáticamente cuando sea necesario destruir el bean para completar el trabajo de limpieza. Los ejemplos son los siguientes:

import javax.annotation.PreDestroy;

public class MyBean {
    private String message;
    
    public void setMessage(String message) {
        this.message = message;
    }
    
    @PreDestroy
    public void cleanup() {
        System.out.println("@PreDestroy: Bean is being destroyed with message: " + message);
    }
}

La destrucción del Bean también se puede especificar a través del archivo de configuración para destruir el método del Bean, usando el atributo destroy-method de la etiqueta <bean> en el archivo de configuración XML para establecer. Los ejemplos son los siguientes:

<bean id="myBean" class="com.example.MyBean" destroy-method="cleanup">
    <property name="message" value="Goodbye World" />
</bean>

4.2.Configuración del método de destrucción de beans y orden de ejecución

Primero se ejecuta el método de destrucción del bean y luego se cierra o destruye el contenedor.

public class Example {
    public static void main(String[] args) {
        // 创建并启动Spring容器
        ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        
        // 获取Bean实例
        MyBean bean = context.getBean(MyBean.class);
        
        // 使用Bean...
        
        // 手动关闭容器
        context.close();
    }
}

En el ejemplo anterior, creamos un objeto ApplicationContext y cargamos un archivo de configuración XML. Al llamar al método getBean() para obtener una instancia de MyBean, el contenedor Spring ejecutará automáticamente el método de destrucción del Bean. Cuando cerramos manualmente el contenedor, podemos llamar al método context.close() para desencadenar la destrucción del Bean.

5. Explicación de las preguntas de la entrevista

5.1.Ciclo de vida del frijol

1. Cargue Spring Bean a través de XML, anotación de Java (anotación) y configuración de Java (clase de configuración), etc.

2.BeanDefinitionReader: analiza la definición de Bean. Durante el proceso de inicio del contenedor Spring, el Bean se analizará en la estructura BeanDefinition dentro de Spring; se entiende que convertir la etiqueta <bean> en spring.xml en la estructura BeanDefinition es algo similar al análisis XML

3.BeanDefinition: contiene muchas propiedades y métodos. Por ejemplo: id, class (nombre de clase), scope, ref (bean dependiente), etc. De hecho, es para almacenar la información de definición del bean (como <bean>) en el atributo correspondiente del BeanDefinition correspondiente, por ejemplo:

<bean id="" class="" scope=""> -----> BeanDefinition(id/clase/alcance)

4.BeanFactoryPostProcessor: es una interfaz de extensión de la función de contenedor Spring.

Aviso:

1) Después de que BeanFactoryPostProcessor cargue BeanDefinition en el contenedor de primavera,

Ejecutado antes de que se cree una instancia del bean

2) Procesar los metadatos del bean (BeanDefinition), es decir, BeanDefinition

Relleno de atributos, modificación y otras operaciones

5. BeanFactory: fábrica de frijoles. Produce los diversos frijoles que necesitamos según nuestros requisitos.

Por ejemplo:

BeanFactory -> Lista<BeanDefinition>

BeanDefinition (id/clase/ámbito/método de inicio)

<bean class="com.zking.spring02.biz.BookBizImpl"/>

foreach(BeanDefinition bean: List<BeanDefinition>){

   //Crear una instancia del objeto de acuerdo con el mecanismo de reflexión del atributo de clase

   // propiedad de configuración de asignación reflexiva

}

6. Interfaz consciente: en el desarrollo real, a menudo es necesario utilizar los recursos funcionales del propio contenedor Spring.

Por ejemplo: BeanNameAware, ApplicationContextAware, etc.

BeanDefinition implementa BeanNameAware, ApplicationContextAware

7.BeanPostProcessor: postprocesador. Después de instanciar e inyectar el objeto Bean, agregue lógica personalizada antes y después de llamar al método de inicialización. (Similar a la notificación circular de AOP) Condición previa: si se detecta que el objeto Bean implementa el posprocesador BeanPostProcessor, se ejecutarán los métodos Before y After

BeanPostProcesador

1)Antes

2) Llame al bean de inicialización (InitializingBean e init-method, la inicialización del bean se considera completa)

3)Después

8.destory: destruir

en conclusión:

1.xml/anotación/configuración configurar JavaBean.

2. BeanDefinitionReader analiza el Javabean configurado para obtener BeanDefinition y finalmente obtiene una colección List.

3. Active BeanFactoryPostProcessor, JavaBean ejecuta su propio negocio antes de la inicialización.

4. BeanFactory en Spring atravesará e inicializará todos los objetos JavaBean a través de la colección List<BeanDefinition> (instanciación de reflexión).

5. Si nuestro propio JavaBean necesita movilizar recursos en el contexto de primavera, entonces debemos implementar la interfaz de percepción *Aware

6. Si su propio JavaBean se ha inicializado y necesita extenderse, debe usar BeanPostProcessor para lograrlo.

7. Destruir (destruir).

5.2 ¿El JavaBean en Spring es una instancia única o múltiple?

1. El valor predeterminado es una sola instancia, pero se pueden configurar varias instancias

2. La ventaja de una sola instancia es ahorrar memoria, pero la desventaja es que hay contaminación variable (la ventaja de múltiples instancias es que no hay contaminación variable, pero consume memoria extremadamente)

Una historia corta y divertida para expresar la diferencia entre instancias únicas y múltiples y las ventajas y desventajas de cada una.


En una escuela de magia de fantasía, hay un maestro especial llamado "Hombre Mágico". Tiene habilidades supermágicas y se encarga de enseñar a los alumnos todo tipo de hechizos mágicos.

Para Magic Man, es un caso único absoluto. Él es el único en toda la escuela con poderes mágicos tan poderosos, y todos los estudiantes y el personal acudirán a él en busca de ayuda y orientación. Siempre está rodeado por el centro de la escuela, y todos persiguen su existencia.

Sin embargo, debido al estado especial de Magic Man, su poder mágico ha impregnado todo el entorno escolar. Ya sea en el salón de clases o en otros lugares de la escuela, está lleno de su atmósfera mágica única. A veces, cuando los estudiantes intentaban lanzar sus hechizos, se veían afectados por el poder de Magicman, que producía efectos inesperados.

En cambio, hay otro maestro llamado "Multiple Clouds". Ella es un caso múltiple y se la puede encontrar en todas las clases. Posee poderes mágicos suaves y flexibles, experta en adaptarse a las necesidades y circunstancias de sus alumnos.

A medida que los estudiantes lanzan sus hechizos bajo la guía de Duodiyun, ella los ayuda a alcanzar su máximo potencial, según el entorno y las necesidades de la clase. Dado que sus poderes mágicos no contaminan la influencia de otras clases, los estudiantes pueden explorar y desarrollar sus habilidades mágicas más libremente.

Esta historia nos dice que las instancias únicas y múltiples tienen sus propias ventajas y desventajas. La ventaja de un singleton radica en la administración y la autoridad centralizadas, pero también es propensa al problema de la contaminación variable. Múltiples instancias pueden proporcionar servicios personalizados para diferentes escenarios, evitando el problema potencial de la contaminación variable.

Al diseñar software, debemos elegir el modo apropiado según las necesidades específicas. Los singletons se pueden usar para situaciones en las que se requiere un acceso unificado global y recursos compartidos. Para escenarios que requieren flexibilidad y sin contaminación variable, los casos múltiples serán una mejor opción. Necesitamos equilibrar las ventajas y desventajas de las instancias únicas y múltiples, y hacer una elección inteligente en función de las necesidades específicas.

Argumento:

ParamAction.java

package com.csdn.xw.aop.beanLife;

import java.util.List;

public class ParamAction {
	private int age;
	private String name;
	private List<String> hobby;
	private int num = 1;
	// private UserBiz userBiz = new UserBizImpl1();

	public ParamAction() {
		super();
	}

	public ParamAction(int age, String name, List<String> hobby) {
		super();
		this.age = age;
		this.name = name;
		this.hobby = hobby;
	}

	public void execute() {
		// userBiz.upload();
		// userBiz = new UserBizImpl2();
		System.out.println("this.num=" + this.num++);
		System.out.println(this.name);
		System.out.println(this.age);
		System.out.println(this.hobby);
	}
}

spring-context.xml

  <bean id="paramAction" class="com.csdn.xw.aop.beanLife.ParamAction">
        <constructor-arg name="name" value="三丰"></constructor-arg>
        <constructor-arg name="age" value="21"></constructor-arg>
        <constructor-arg name="hobby">
            <list>
                <value>抽烟</value>
                <value>烫头</value>
                <value>大保健</value>
            </list>
        </constructor-arg>
    </bean>

Clase de prueba de prueba

package com.csdn.xw.aop.beanLife;

import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

/*
 * spring	bean的生命週期
 * spring	bean的單例多例
 */
public class Demo2 {
	// 体现单例与多例的区别
	@Test
	public void test1() {
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml");
//		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml");
		ParamAction p1 = (ParamAction) applicationContext.getBean("paramAction");
		ParamAction p2 = (ParamAction) applicationContext.getBean("paramAction");
		// System.out.println(p1==p2);
		p1.execute();
		p2.execute();
		
//		单例时,容器销毁instanceFactory对象也销毁;多例时,容器销毁对象不一定销毁;
		applicationContext.close();
	}

	// 体现单例与多例的初始化的时间点 instanceFactory
	@Test
	public void test2() {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml");
	}

	// BeanFactory会初始化bean对象,但会根据不同的实现子类采取不同的初始化方式
	// 默认情况下bean的初始化,单例模式立马会执行,但是此时XmlBeanFactory作为子类,单例模式下容器创建,bean依赖没有初始化,只有要获取使用bean对象才进行初始化
	@Test
	public void test3() {
		// ClassPathXmlApplicationContext applicationContext = new
		// ClassPathXmlApplicationContext("/spring-context.xml");

		Resource resource = new ClassPathResource("/spring-context.xml");
		BeanFactory beanFactory = new XmlBeanFactory(resource);
//		InstanceFactory i1 = (InstanceFactory) beanFactory.getBean("instanceFactory");
		
	}

}

resultado de la operación:

Esta vez configuramos manualmente varias instancias de scope="prototype" y echamos un vistazo

5.3 ¿Cuándo se crean JavaBean de instancia única y JavaBean de múltiples instancias?

 Caso único: JavaBean se inicializa con el contexto Spring, el objeto del contenedor nace y el objeto del contenedor está muerto

 Múltiples ejemplos: JavaBean se crea cuando se usa y se destruye siguiendo la JVM

Argumento:

InstanceFactory.java

package com.csdn.xw.aop.beanLife;

public class InstanceFactory {
	public void init() {
		System.out.println("初始化方法");
	}

	public void destroy() {
		System.out.println("销毁方法");
	}

	public void service() {
		System.out.println("业务方法");
	}
}

spring-context.xml

  <bean id="instanceFactory" class="com.csdn.xw.aop.beanLife.InstanceFactory"
          scope="prototype" init-method="init" destroy-method="destroy"></bean>

Puede ver que la configuración xml anterior tiene varias instancias. Llamemos a test2 para ver si nuestra "inicialización de Bean" está lista.

Se puede ver que no hay, porque solo obtenemos el objeto context de spring y no el objeto Bean, ahora cambiamos a singleton scope="singleton" para ver el resultado.

 En este momento, descubrimos que JavaBean se ha creado independientemente de si hemos obtenido el objeto Bean o no.

Resumen: ¿Por qué se inicializa el singleton después de crear el contenedor? Porque la idea de un singleton es crearlo sin importar cuando lo uses, si esperas a que tu navegador envíe una solicitud para crearlo, reducirá mucho la experiencia del usuario, de todos modos, solo se creará una vez. ¿Por qué no crearlo cuando inicias el proyecto? De acuerdo, consume mucho tiempo en el proyecto de inicio. Si hay varias instancias, ¿creará cien si hay cien? Creas mil, ¿y si tengo mil y solo uso uno? Los 999 restantes se desperdician, por lo que solo se crearán varias instancias cuando las use.

5.4 ¿ Inicializaremos JavaBean cuando usemos un singleton?

BeanFactory inicializará los objetos bean, pero adoptará diferentes métodos de inicialización de acuerdo con las diferentes subclases de implementación. De forma predeterminada, la inicialización del bean se ejecutará inmediatamente en modo singleton, pero en este momento se utiliza XmlBeanFactory como subclase. Creación de contenedores en modo singleton, beans La dependencia no se inicializa, solo para que se inicialice el objeto bean.

Argumento:

Llame a test3 para verificar los resultados

Como una subclase de XmlBeanFactory, el contenedor se crea en modo singleton y la dependencia del bean no se inicializa, así que vamos a obtenerlo y usarlo.

 En este punto se crea el Bean.

Mi intercambio está aquí, ¡bienvenido al área de comentarios para discutir y comunicarnos! !

Si lo encuentras útil, por favor dale me gusta ♥ ♥

Supongo que te gusta

Origin blog.csdn.net/weixin_74318097/article/details/132358501
Recomendado
Clasificación