SpringIOC detallado: lo que sorprende al entrevistador no es el ensayo memorizado de ocho partes, sino la profundidad y amplitud de la tecnología

preguntas de entrevista

De la tortura del entrevistador desde lo más profundo del alma: habla de tu comprensión de la primavera;

La actividad interior del buscador de trabajo confundido: ¿qué? ¿Cuál es el problema específico? ¿Están las entrevistas ahora fuera del camino? ¿Cómo me pides que responda una pregunta tan grande?

El buscador de trabajo desconcertado respondió: Uh ~ ~ ~ esto. . . . Uh ~ ~ ~ eso. . . . Cantidad ~ ~ ~ No sé. . .

¿Por qué el entrevistador hace este tipo de preguntas?

Es innegable que la mayoría de las preguntas de las entrevistas actuales son así. Es sorprendentemente similar. Al entrevistador le gusta lanzar una pregunta para ver qué tan profundo puede hablar. La prueba es su profundidad y amplitud de esta tecnología. La profundidad es su comprensión de la tecnología subyacente, la amplitud es el ámbito de aplicación de esta tecnología y la dirección de expansión.

En ese momento, un compañero de clase de gángsters está a punto de preguntar: "¿Por qué necesitas saber estas cosas de bajo nivel? Solo necesito saber cómo usarlas. Siempre construyo cohetes durante las entrevistas, pero me hacen atornillar tornillos durante las entrevistas reales". trabajo". Aunque es cierto, lo que debe considerar es que todos pueden usar esta cosa, y no solo usted. Ya que todos saben algo, ¿y si refleja su valor? Esto debe tener en cuenta la profundidad. Xiaohong y Xiaoming usan resorte, pero Xiaoming conoce su mecanismo y principio de ejecución subyacente. Cabe señalar aquí que la profundidad de su respuesta determina su salario y tratamiento, lo cual es muy importante. , ¿cómo lo hacemos? ¿Responde esta pregunta? De hecho, es muy simple, primero ordena el contexto general y luego explícalo en profundidad uno por uno; he escrito blogs como este desde este año, y elaboraré la explicación de lo más superficial a lo más profundo, y lo haré. proporcione el código y el diagrama de flujo.

Como programador, si desea desarrollarse en la dirección de un experto, debe comprender la idea de programación, el principio de ejecución subyacente del algoritmo, y el código es el segundo, porque solo hay un principio, y no Hay varios métodos de implementación. Una interfaz permite que 10.000 personas escriban la realización, la realización de diez mil personas no será la misma, esta es la importancia de pensar.

COI de primavera

Antes que nada, antes de eso, primero debemos saber qué es ioc, ioc se llama inversión de control, y también se le puede llamar inyección de dependencia (DI), de hecho, inyección de dependencia es otro término para ioc.

1. ¿Quién controla a quién? : En el pasado, la creación y destrucción de objetos eran controladas por el usuario. Después de usar ioc, la creación y destrucción de objetos están controladas por el contenedor. El usuario no necesita preocuparse por estos, solo enfóquese en las necesidades comerciales;

2. ¿Qué es la inversión? : Dado que se llama inversión, debe haber rotación hacia adelante. La rotación hacia adelante es en realidad el objeto que busca la instancia, y la rotación inversa se invierte, para que la instancia encuentre el objeto; ¿cómo encontrarlo? ¡A través del contenedor, por supuesto!

3. ¿Quién depende de quién? : En el proyecto de primavera, el objeto se entiende como un bean, que también puede llamarse un objeto bean. Hay una dependencia entre el bean y el contenedor. La creación del objeto bean depende del contenedor, al igual que el niño depende en el padre, y el niño no puede dar a luz a sí mismo. , requiere la cooperación de los padres para nacer, el niño aquí es el frijol y el padre es el contenedor;

4. ¿Quién inyecta a quién? : El objeto bean se inyecta a través del contenedor y este proceso está automatizado, es decir, el contenedor encontrará automáticamente una instancia de tipo que coincida con el objeto bean y lo inyectará en el objeto;

El proceso de carga de spring ioc

Después de comprender la inversión del control y la inyección de dependencia, echemos un vistazo al proceso de carga de ioc. Todo el proceso de carga de ioc se muestra en la figura a continuación. Primero, mire el proceso general y luego profundice (el cuadro amarillo es el contenido del comentario)

1. Primero, lea el archivo de configuración especificado a través de BeanDefinitionReader para generar información de definición de bean, y luego vaya a la información de definición de bean completa (objeto BeanDefinition).Tenga en cuenta que solo la información de definición del bean se almacena aquí, y el objeto bean no tiene ha sido instanciado; al igual que en la fábrica Lo mismo, la materia prima está lista, pero aún no se ha producido, la materia prima es el grano Definición, y la producción es la instanciación

2. A través de un potenciador posterior entre BeanDefinition y el BeanDefinition completo, la información de definición del bean se puede modificar de manera uniforme. Solo necesita implementar la interfaz BeanFactoryPostProcessor. Puede haber múltiples potenciadores posteriores. Una clase que implementa múltiples BeanFactoryPostProcessors luego ejecute varias veces, así:

package com.Spring.Boot.init;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
/**
 * 扩展方法--后置增强器(可修改bean的定义信息)
 */
@Component
public class ExtBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
//        BeanDefinition studentService = beanFactory.getBeanDefinition("studentService");
        System.out.println("扩展方法--可进行修改beanDefinition的定义信息");
    }
}
复制代码

3. Después de obtener la BeanDefinition completa, puede crear un objeto. Todo este proceso se denomina ciclo de vida de un bean, que es el proceso desde la instanciación hasta la destrucción. ¿Hay tantos problemas? ¿No es suficiente instanciar un objeto? directamente por reflexión? ¿Por qué hay inicialización?"; En primer lugar, esta es una buena pregunta, vamos, demos un aplauso al estudiante que hizo la pregunta; lo que quiero decir es, incluso si sale un nuevo objeto ordinario , será instanciado e inicializado en él A continuación, nos centraremos en el ciclo de vida de los beans;

Ciclo de vida de Spring Bean

En términos generales, el ciclo de vida de los frijoles se divide principalmente en los siguientes 4 pasos

Pero, de hecho, contiene muchas cosas adentro, echemos un vistazo al diagrama de flujo refinado;

¿Qué tal? ¿Viste muchas cosas que no habías visto antes? Parece que conozco algunos, pero la mayoría son cosas que no he visto antes. No importa si no lo sé. A continuación, los explicaremos uno por uno.

A continuación, uniremos 1, 3 y 4 porque están en la misma interfaz y se puede implementar la interfaz InstatiationAwareBeanPostProcessor.

package com.Spring.Boot.init;
 
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.stereotype.Component;
 
@Component
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
 
    // 实例化前置
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        
        System.out.println("postProcessBeforeInstantiation被调用了----在对象实例化之前调用-----beanName:" + beanName);
        // 默认什么都不做,返回null
        return null;
    }
 
    // 实例化后置
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInstantiation被调用了---------beanName:" + beanName);
        //默认返回true,什么也不做,继续下一步
        return true;
    }
    
    // 属性修改
    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
        System.out.println("postProcessPropertyValues被调用了---------beanName:"+beanName);
        // 此方法可对bean中的属性值进行、添加、修改、删除操作;
        // 对属性值进行修改,如果postProcessAfterInstantiation方法返回false,该方法可能不会被调用,
        return pvs;
    }
}
复制代码

A continuación explicamos a su vez

1. Crea una instancia del front-end

El método InstatiationAwareBeanPostProcessor.postProcessBeforeInstantiation(Class<?> beanClass, String beanName) se usa antes de la creación de instancias. Hay dos parámetros en el método, a saber, beanClass y beanName. Como su nombre lo indica, es la información de clase del objeto bean antes del se instancia el objeto.Para modificar o expandir para lograr las funciones que queremos, su capa inferior se implementa mediante la tecnología AOP de proxy dinámico y es el primer método que se ejecuta en el ciclo de vida del bean;

Retorno no nulo: el valor de retorno es de tipo Objeto, lo que significa que podemos devolver cualquier tipo de valor. Dado que el objeto de destino no se ha instanciado en este momento, este valor de retorno se puede utilizar para reemplazar la instancia del objeto de destino. que debería haber generado el objeto, y también Es decir, si se devuelve un valor no nulo, entonces cuando necesitemos usar este bean en el futuro, obtendremos el objeto devuelto ahora, y no iremos a la segundo paso para instanciar el objeto;

Devuelve un valor vacío (nulo): el valor predeterminado es devolver un valor nulo, luego regresar directamente y luego llamar al método doCreateBean para instanciar el objeto;

2. Crea una instancia del objeto

El método doCreateBean crea una instancia y usa tecnología de reflexión para crearla. No hay nada que decir al respecto. Es simplemente equivalente a crear un objeto. Sin embargo, debe tenerse en cuenta que en este momento, el objeto solo se instancia y el no se han establecido las propiedades en el objeto;

3. Crea una instancia de la publicación

方法名称: InstanciationAwareBeanPostProcessor.postProcessAfterInstantiation(Object bean, String beanName)

Se llama después de que se crea una instancia del objeto de destino. En este momento, se ha creado una instancia del objeto, pero las propiedades de la instancia no se han establecido y todas son nulas. Porque su valor de retorno es un factor para decidir si llamar al método postProcessPropertyValues ​​(porque hay otro factor que es mbd.getDependencyCheck());

Devolver falso: si el método devuelve falso y no se requiere verificación, entonces postProcessPropertyValues ​​​​se ignorará y no se ejecutará;

Devuelve verdadero: Si devuelve verdadero, se ejecutará postProcessPropertyValues

4. Modificación de la propiedad

方法名称 :InstantiationAwareBeanPostProcessor.PropertyValues ​​postProcessPropertyValues(PropertyValues ​​pvs, PropertyDescriptor[] pds, Object bean, String beanName)

Este método puede modificar el valor del atributo, y el alcance de la modificación incluye agregar, modificar y eliminar operaciones; si el método postProcessAfterInstantiation() devuelve falso después de la creación de instancias, no se llamará a este método;

5. Asignar valores a los atributos de los usuarios

Los atributos de usuario se refieren a los atributos de objeto de bean personalizados por Spring People. Los objetos como User, Student, Teacher, UserService e IndexService son todos objetos de bean personalizados. El quinto paso es asignar valores a dichos atributos, utilizando AbstractAutowireCapableBeanFactory método .populateBean() para asignar valores;

6. Asignar valores a las propiedades del contenedor

Las propiedades del contenedor son en realidad las propiedades que vienen con el contenedor. Estas propiedades son todas inherentes a Spring; es seguro que todas son clases de implementación de la interfaz Aware. Existen principalmente las siguientes clases de implementación, y he organizado su orden de ejecución ahora,

Veamos cómo usarlo primero, y luego expliquemos el rol de cada Aware; el código de arriba

package com.Spring.Boot.init.aware;
 
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.*;
import org.springframework.context.annotation.ImportAware;
import org.springframework.context.weaving.LoadTimeWeaverAware;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.instrument.classloading.LoadTimeWeaver;
import org.springframework.stereotype.Component;
import org.springframework.util.StringValueResolver;
import org.springframework.web.context.ServletContextAware;
import javax.servlet.ServletContext;
 
@Component
public class AllAwareInterface  implements BeanNameAware, BeanClassLoaderAware,
        BeanFactoryAware, EnvironmentAware, EmbeddedValueResolverAware,
        ResourceLoaderAware, ApplicationEventPublisherAware, MessageSourceAware,
        ApplicationContextAware, ServletContextAware, LoadTimeWeaverAware, ImportAware {
 
    @Override
    public void setBeanName(String name) {
        // BeanNameAware作用:让Bean对Name有知觉
        //这个方法只是简单的返回我们当前的beanName,听官方的意思是这个接口更多的使用在spring的框架代码中,实际开发环境应该不建议使用
        System.out.println("1 我是 BeanNameAware 的 setBeanName 方法  ---参数:name,内容:"+ name);
    }
    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        System.out.println("2 我是 BeanClassLoaderAware 的 setBeanClassLoader 方法");
    }
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        // 注意: 如果使用 @Configuration 注解的话,setBeanFactory方法会执行2次,
        System.out.println("3 我是 BeanFactoryAware 的 setBeanFactory 方法");
    }
    @Override
    public void setEnvironment(Environment environment) {
        System.out.println("4 我是 EnvironmentAware 的 setEnvironment 方法");
    }
    @Override
    public void setEmbeddedValueResolver(StringValueResolver stringValueResolver) {
        System.out.println("5 我是 EmbeddedValueResolverAware 的 setEmbeddedValueResolver 方法");
    }
    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        System.out.println("6 我是 ResourceLoaderAware 的 setResourceLoader 方法");
    }
    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        System.out.println("7 我是 ApplicationEventPublisherAware 的 setApplicationEventPublisher 方法");
    }
    @Override
    public void setMessageSource(MessageSource messageSource) {
        System.out.println("8 我是 MessageSourceAware 的 setMessageSource 方法");
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("9 我是 ApplicationContextAware 的 setApplicationContext 方法");
    }
    @Override
    public void setServletContext(ServletContext servletContext) {
        System.out.println("10 我是 ServletContextAware 的 setServletContext 方法");
    }
    @Override
    public void setLoadTimeWeaver(LoadTimeWeaver loadTimeWeaver) {
        //LoadTimeWeaver 简称LTW,LTW是AOP的一种实现方式,此方法是为了获取Aop织入的对象,使用的织入方式是:类加载期织入,
        // 一般的aop都是运行期织入,就是在运行的时候才进行织入切面方法,但是LTW是在类加载前就被织入了,也就是class文件在jvm加载之前进行织入切面方法
        // 只有在使用 @EnableLoadTimeWeaving 或者存在 LoadTimeWeaver 实现的 Bean 时才会调用,顺序也很靠后
        System.out.println("11 我是 LoadTimeWeaverAware 的 setLoadTimeWeaver 方法");
    }
    @Override
    public void setImportMetadata(AnnotationMetadata annotationMetadata) {
        //只有被其他配置类 @Import(XX.class) 时才会调用,这个调用对 XX.class 中的所有 @Bean 来说顺序是第 1 的。
        System.out.println("12 我是 ImportAware 的 setImportMetadata 方法");
    }
}
复制代码

Algunos de los resultados impresos en la consola después de comenzar la primavera son los siguientes:

Puede ver que sus resultados de salida se imprimen en orden, que es su orden estándar; a continuación, comprendamos sus funciones específicas

6.1 BeanNameAware.setBeanName ()

Este método simplemente devuelve nuestro beanName actual. El significado oficial es que esta interfaz se usa más en el código del marco de Spring, y no se debe recomendar el entorno de desarrollo real.

6.2 BeanClassLoaderAware.setBeanClassLoader()

Obtener el cargador de clases del bean,

6.3 BeanFactoryAware.setBeanFactory()

Obtener la fábrica de frijoles La fábrica de frijoles le permite leer los objetos en el contenedor IOC a voluntad sin depender del método de inyección, pero la fábrica de frijoles aún necesita ser inyectada.

Cabe señalar que, en general, usamos la anotación @Component, si se usa la anotación @Configuration, el método setBeanFactory se ejecutará dos veces;

6.4 Consciente del Medio Ambiente.setEnvironment()

Después de implementar la interfaz EnvironmentAware y reescribir el método setEnvironment, los valores de propiedad configurados en los archivos de configuración de application.properties, xml y yml se pueden obtener cuando se inicia el proyecto.

6.5 EmbeddedValueResolverAware.setEmbeddedValueResolver ()

Por lo general, usamos la anotación @Value para obtener los valores en las propiedades y los archivos yml. También es muy engorroso usar @Value en cada clase. Es mucho más conveniente después de implementar la interfaz EmbeddedValueResolverAware. El uso es el mismo que el de @Value, debe incluirse en ${};

@Component   
public class PropertiesUtil implements EmbeddedValueResolverAware {
 
	@Override
	public void setEmbeddedValueResolver(StringValueResolver stringValueResolver) {   
     System.out.println(stringValueResolver.resolveStringValue("${logging.file}"));
	}
}
复制代码

6.6 ResourceLoaderAware.setResourceLoader()

Spring ResourceLoader nos proporciona un método getResource() unificado para recuperar recursos externos a través de la ruta de recursos. Hay diferentes implementaciones para cargar recursos o archivos (como archivos de texto, archivos XML, archivos de propiedades o archivos de imagen) en el contexto de la aplicación Spring. De hecho, se usa para cargar recursos externos, hay un parámetro en el método: ResourceLoader , Este parámetro es en realidad ApplicationContext (objeto de contexto de Spring); se puede forzar directamente;

package org.crazyit.app.service;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.ResourceLoader;
public class TestBean implements ResourceLoaderAware{
   
    public void setResourceLoader(ResourceLoader resourceLoader) {
        // 可直接强转为 ApplicationContext
        ApplicationContext context = (ApplicationContext) resourceLoader;
 
        System.out.println("6 我是 ResourceLoaderAware 的 setResourceLoader 方法");
    }
   
}
 
复制代码

y podemos especificar diferentes prefijos para crear rutas para cargar recursos desde diferentes ubicaciones

6.7 ApplicationEventPublisherAware.setApplicationEventPublisher();

ApplicationEventPublisherAware es una interfaz de publicación de eventos. Usando esta interfaz, nuestro propio Servicio tiene la capacidad de publicar eventos. Después de que el usuario se registra, en lugar de llamar a otros servicios comerciales, se publica un evento de registro de usuario. Así que aquí está el evento de publicación, luego debe haber una interfaz para monitorear eventos. Esta interfaz se llama ApplicationListener. Mientras la interfaz de ApplicationListener esté implementada, los eventos publicados pueden ser aceptados. A continuación, escribiremos un ejemplo para simular eventos de publicación. y escuchar eventos;

Primero cree una clase de entidad para almacenar el contenido del evento publicado StringEvent.java

package com.Spring.Boot.init.listener.eventModel;
import org.springframework.context.ApplicationEvent;
//事件监听对象
public class StringEvent extends ApplicationEvent {
 
    private String str;
    // 构造函数
    public StringEvent(Object source) {
        super(source);
        str = source.toString();
    }
    // 获取字符串
    public String getStr(){
        return str;
    }
}
复制代码

Cree una clase que publique eventos: ExtApplicationEventPublisherAware.java, implemente la interfaz ApplicationEventPublisherAware para aumentar la función de publicación de eventos;

package com.Spring.Boot.init.aware;
 
import com.Spring.Boot.init.listener.eventModel.StringEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;
 
/**
 * 发布事件
 */
@Component
public class ExtApplicationEventPublisherAware implements ApplicationEventPublisherAware {
    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        System.out.println("发布事件,事件对象为 StringEvent ,内容为 :1234");
        StringEvent stringEvent = new StringEvent("1234");
        // 发布事件 ,发布后会在 ApplicationListener.onApplicationEvent()方法进行捕获;
        applicationEventPublisher.publishEvent(stringEvent);  // 发布事件
    }
}
复制代码

Cree un detector de eventos: EventListener.java para escuchar todos los eventos publicados;

package com.Spring.Boot.init.listener;
 
 
import com.Spring.Boot.init.listener.eventModel.StringEvent;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
 
//事件监听器
@Component
public class EventListener implements ApplicationListener<StringEvent> {
 
    @Override
    public void onApplicationEvent(StringEvent o) {
        System.out.println("监听到事件,内容:"+o.getStr());
    }
}
复制代码

A continuación, ejecute el proyecto de primavera y vea los resultados impresos de la siguiente manera: en este punto, se completan la publicación y el seguimiento del evento;

6.8 MessageSourceAware.setMessageSource()

Operaciones de notificación de mensajes internacionalizados

6.9 ApplicationContextAware.setApplicationContext()

ApplicationContextAware se usa principalmente para obtener el contexto ApplicationContext globalmente. ApplicationContext es en realidad un contenedor. Por esta razón, podemos implementar la interfaz ApplicationContextAware para obtener el objeto contenedor ApplicationContext, podemos convertirlo en una clase estática pública, para que podamos llevarlo a cualquier parte. queremos.

package com.Spring.Boot.init.aware;
 
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
 
@Component
public class ExtApplicationContextAware implements ApplicationContextAware {
 
    /**
     * Spring容器会在加载完Spring容器后调用ApplicationContextAware.setApplicationContext方法
     * ApplicationContextAware 主要用来全局获取 ApplicationContext 上下文,
     */
 
    private static ApplicationContext applicationContext;
 
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (ExtApplicationContextAware.applicationContext == null) {
            ExtApplicationContextAware.applicationContext = applicationContext;
        }
        System.out.println("========ApplicationContext配置成功========");
        System.out.println("========在普通类可以通过调用SpringBootBeanUtil.getApplicationContext()获取applicationContext对象========");
        System.out.println("========applicationContext="+ ExtApplicationContextAware.applicationContext +"========");
    }
 
    /**
     * 获取applicationContext
     * @return
     */
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }
 
    /**
     * 通过name获取 Bean.
     * @param name
     * @return
     */
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }
 
    /**
     * 通过class获取Bean.
     * @param clazz
     * @return
     */
    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }
 
    /**
     * 通过name,以及Clazz返回指定的Bean
     * @param name
     * @param clazz
     * @return
     */
    public static <T> T getBean(String name, Class<T> clazz) {
        return getApplicationContext().getBean(name, clazz);
    }
 
}
复制代码

Por supuesto, también se puede inyectar directamente, así:

    @Autowired
    private ApplicationContext applicationContext;
复制代码

6.10 ServletContextAware.setServletContext()

Al implementar la interfaz ServletContextAware, se puede obtener el servletContext, que es el contexto del servlet;

Qué es ServletContext: cuando se inicia el contenedor WEB, creará un objeto ServletContext correspondiente para cada aplicación WEB, que representa la aplicación web actual. La referencia del objeto ServletContext se mantiene en el objeto ServletConfig.Cuando los desarrolladores escriben servlets, pueden obtener el objeto ServletContext a través del método ServletConfig.getServletContext.

Dado que todos los servlets en una aplicación WEB comparten el mismo objeto ServletContext, la comunicación entre los objetos servlet se puede lograr a través del objeto ServletContext. El objeto ServletContext también se conoce comúnmente como el objeto de dominio de contexto.

6.11 LoadTimeWeaverAware.setLoadTimeWeaver ()

De hecho, todavía hay 2 sin imprimir durante la depuración. El 11 es LoadTimeWeaver, denominado LTW. LTW es una implementación de AOP. Este método es para obtener los objetos tejidos por Aop. El método de tejido utilizado es: class Loading time weaving, aop general es tejido de tiempo de ejecución, es decir, tejido del método de aspecto en tiempo de ejecución, pero LTW se entrelaza antes de que se cargue la clase, es decir, el archivo de clase se entrelaza antes de que se cargue jvm. El método de entrada se llama solo cuando @EnableLoadTimeWeaving se utiliza o cuando hay un bean implementado por LoadTimeWeaver, y la orden es muy tarde;

6.12 ImportAware.setImportMetadata()

Otra cosa que no está impresa es la interfaz ImportAware, los métodos de esta interfaz solo se llamarán cuando se llame a otras clases de configuración @Import(XX.class), esta llamada es la primera orden para todos los @Beans en XX.class.

7. Inicializar el frente

Nombre del método: BeanPostProcessor.postProcessBeforeInitialization()

El método a ejecutar antes de inicializar cada bean (tantos beans como veces)

Nota: Después de habilitar este método, el método anotado con @PostConstruct no será válido

8. Inicializar la publicación

Nombre del método: BeanPostProcessor.postProcessAfterInitialization ()

El método a ejecutar después de inicializar cada bean (tantos beans como veces)

El código de implementación de la inicialización previa y posterior a la inicialización es el siguiente

package com.Spring.Boot.init;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
 
@Component
public class ExtBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 在每一个 Bean 初始化之前执行的方法(有多少 Bean 调用多少次)
        // 注意 : 启用该方法后,标注了@PostConstruct注解的方法会失效
        System.out.println("初始化前置方法");
        return null;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
         在每一个 Bean 初始化之后执行的方法(有多少 Bean 调用多少次)
        System.out.println("初始化后置方法");
        return null;
    }
}

复制代码

9. Ejecute el método de inicialización

Hay tres métodos de inicialización, a saber, el método de agregar la anotación @PostConstruct, implementar la interfaz InitializingBean y agregar el atributo initMethod a la anotación @bean; hablaremos de ellos uno por uno.

10. Método de inicialización 1: @PostConstruct

Después de agregar la anotación @PostConstruct al objeto bean, se puede realizar la función de inicialización. El método modificado por @PostConstruct se ejecutará después del constructor y antes del método init(). Si hay más de uno, se ejecutará varias veces;

Nota: si Spring implementa el método postProcessBeforeInitialization() de la interfaz BeanPostProcessor, que es el método de publicación inicial de 12, entonces la anotación @PostConstruct no será válida;

ejemplo de código

package com.Spring.Boot.init;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
 
// @PostConstruct注解
@Component
public class ExtPostConstruct {
 
    /**
     * 被@PostConstruct修饰的方法会在构造函数之后,init()方法之前运行。如果有多个则会执行多次
     * 注意: 如果spring 实现了 BeanPostProcessor接口的postProcessBeforeInitialization方法,该@PostConstruct注解会失效
     */
    @PostConstruct
    public void init() {
        System.out.println("第一个init...");
    }
 
    // 有多个会执行多次
    @PostConstruct
    public void init1() {
        System.out.println("第二个init1...");
    }
 
}

复制代码

11, InicializandoBean.afterPropertiesSet()

Uno de los métodos de inicialización de primavera es realizar un comportamiento de inicialización personalizado después de que BeanFactory complete la configuración de la propiedad.

Orden de ejecución: antes de initMethod, después de @PostConstruct

ejemplo de código

package com.Spring.Boot.init;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
 
@Component
public class ExtInitializingBean implements InitializingBean {
    @Override
    public void afterPropertiesSet() throws Exception {
        // 一个 InitializingBean 执行一次
        // spring 初始化方法,作用是在BeanFactory完成属性设置之后,执行自定义的  初始化行为.
        // 执行顺序:在initMethod之前执行,在@PostConstruct之后执行
        System.out.println("InitializingBean");
    }
}

复制代码

12, método de inicio

El atributo init-method del archivo de configuración del bean se usa para especificar el método de ejecución cuando se inicializa el bean, en lugar de heredar la interfaz InitializingBean,

Una cosa a tener en cuenta es que el método de inicialización solo se puede usar después de que se haya creado una instancia completa de la clase.

Código de ejemplo, primero defina una clase: BeanTest.java, defina un método de inicialización initMethod_1() en la clase

package com.Spring.Boot.init.bean;
 
public class BeanTest {
    
    // 将要执行的初始化方法
    public void initMethod_1(){
        System.out.println("我是beanTest的init方法");
    }
}

复制代码

método de configuración xml

<bean id="beanTest" class="com.BeanTest" init-method="init"></bean> método de configuración de anotaciones

package com.Spring.Boot.init;
import com.Spring.Boot.init.bean.BeanTest;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component()
public class InitMethod  {
    
    // 在@Bean注解上添加initMethod属性,指向类中的 initMethod_1 执行初始化方法
    @Bean(initMethod = "initMethod_1")
    public BeanTest getBeanTest(){
        return new BeanTest();
    }
}
复制代码

13. En uso

En este punto, el objeto bean se ha creado por completo, es un objeto completo y está siendo utilizado por otros objetos;

14. Proceso de destrucción

Primero debe decirse que los beans administrados por el contenedor Spring son singleton de forma predeterminada, y hay una anotación @Scope en la clase de forma predeterminada, que es así

package com.Spring.Boot.init;
 
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
 
@Component()
@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
// @Scope(value = "singleton")  // 也可以这样写
public class InitMethod  {
 
  // methods....
 
}
复制代码

Si desea establecerlo en instancias múltiples, solo necesita cambiar el valor de la propiedad de @Scope. De esta manera, el modo de instancia múltiple también se denomina modo prototipo. La capa inferior no es para recrear un objeto de frijol, sino para utilizar la tecnología de copia profunda, es copiar un objeto y utilizarlo

@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
// @Scope(value = "prototype") // 也可以这样写
复制代码

¿Por qué introducir instancias únicas y múltiples? Porque ah, la dirección del proceso de destrucción está relacionada con si eres único o múltiple;

Si se trata de un modo singleton, primero se ejecutará el método DiscoverBean.destroy() y luego se ejecutará el método destroy-Method;

14.1 Frijol Desechable.destroy()

Método de destrucción del modo singleton, código de muestra

package com.Spring.Boot.init.destroy;
 
import org.springframework.beans.factory.DisposableBean;
import org.springframework.stereotype.Component;
 
/**
 * 销毁方法
 */
@Component
public class ExtDisposableBean implements DisposableBean {
    @Override
    public void destroy() throws Exception {
        System.out.println("我被销毁了");
    }
}
复制代码

Cuando finaliza el método principal, el resultado impreso en la consola es el siguiente

14.2 Método del método de la historia

Tomemos el ejemplo del proceso 11, pero esta vez agregamos el atributo destroyMethod a la anotación @Bean, apuntando al método de destrucción: destroyMethod_1()

package com.Spring.Boot.init;
 
import com.Spring.Boot.init.bean.BeanTest;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
 
@Component()
public class InitMethod  {
 
    // 在@Bean注解上添加initMethod属性,指向类中的 initMethod_1 执行初始化方法
    // 在@Bean注解上添加destroyMethod属性,指向类中的 destroyMethod_1 执行销毁方法
    @Bean(initMethod = "initMethod_1",destroyMethod = "destroyMethod_1")
    public BeanTest getBeanTest(){
        return new BeanTest();
    }
}
BeanTest.java

package com.Spring.Boot.init.bean;
 
public class BeanTest {
 
    // 将要执行的初始化方法
    public void initMethod_1(){
        System.out.println("我是beanTest的init方法");
    }
 
    // 将要执行的销毁方法
    public void destroyMethod_1(){
        System.out.println("我是beanTest的init方法");
    }
 
 
}
复制代码

configuración xml

<bean id="beanTest" class="com.BeanTest" destroy-method="destroyMethod_1"></bean>

15. Devuelva el bean al usuario y el usuario controlará el resto del ciclo de vida

Debido a que Spring no puede administrar en el modo de instancias múltiples, el ciclo de vida se entrega al usuario.Después de que el usuario se quede sin objetos de frijol, el procesador de basura de Java reciclará automáticamente los objetos inútiles;


Autor: Java Architect
Enlace: https://juejin.cn/post/6966158157202587662
Fuente: Rare Earth Nuggets
Los derechos de autor pertenecen al autor. Para reimpresiones comerciales, comuníquese con el autor para obtener autorización, y para reimpresiones no comerciales, indique la fuente.

Supongo que te gusta

Origin blog.csdn.net/wdjnb/article/details/124295494
Recomendado
Clasificación