[Question d'entrevue] Le cycle de vie des haricots au printemps, la différence entre le DI et l'IoC de Spring

Premièrement, le cycle de vie des haricots au printemps

class -> BeanDefinition -> nouvel objet (objet d'origine) -> propriété de remplissage -> initialisation -> bean join singleton pool

Le cycle de vie du bean est principalement: construction (instanciation) -> injection de propriété (set) -> avant initialisation -> initialisation -> après initialisation -> rejoindre le pool de singleton à utiliser -> détruire

1. Quatre étapes principales

Le cycle de vie d'un haricot printanier ne comporte que quatre étapes principales, et les autres sont des points d'extension avant et après ces quatre étapes principales . Les quatre étapes sont:

  1. Instanciation ---> méthode de construction
  2. Attribution d'attribut Remplir ---> injection setter ()
  3. Initialisation
  4. Destruction

Parmi eux, l' instanciation et l'attribution d'attributs correspondent respectivement à l'injection de la méthode de construction et de la méthode setter ; l'initialisation et la destruction sont deux étapes que les utilisateurs peuvent personnaliser et développer ; l' attribution d'attributs Populate est principalement utilisée pour remplir les propriétés dépendantes parmi plusieurs beans .

Il peut être trouvé en vérifiant le code source qu'ils sont tous dans la méthode doCreateBean (),

// 忽略了无关代码
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
      throws BeanCreationException {

   // Instantiate the bean.
   BeanWrapper instanceWrapper = null;
   if (instanceWrapper == null) {
       // 实例化阶段!
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }

   // Initialize the bean instance.
   Object exposedObject = bean;
   try {
       // 属性赋值阶段!
      populateBean(beanName, mbd, instanceWrapper);
       // 初始化阶段!
      exposedObject = initializeBean(beanName, exposedObject, mbd);
   }

   
   }

On peut constater que trois méthodes sont appelées séparément:

  1. createBeanInstance () -> instanciation
  2. populateBean () -> attribution d'attribut
  3. initializeBean () -> initialisation

La phase de destruction est appelée lorsque le conteneur est fermé , dans le close () de la classe ConfigurableApplicationContext

2. Points d'extension couramment utilisés

2.1 Interfaces qui affectent plusieurs beans

Les deux interfaces les plus importantes:

  • InstantiationAwareBeanPostProcessor : front de phase d' instanciation agissant
  • BeanPostProcessor: action sur la phase d' initialisation avant et après

Les beans qui implémentent ces deux interfaces seront automatiquement découpés dans le cycle de vie correspondant

Le code spécifique est le suivant:

package cn.xmx.ioc.lifecycle;

import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;

import java.beans.PropertyDescriptor;

public class MyInstantiationAwareBeanPostProcessorAdapter extends InstantiationAwareBeanPostProcessorAdapter {
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if(beanName.equals("car")){
            System.out.println(beanName+"在实例化之前");
        }

        return super.postProcessBeforeInstantiation(beanClass, beanName);
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if(beanName.equals("car")){
            System.out.println(beanName+"在实例化之后");
        }
        return super.postProcessAfterInstantiation(bean, beanName);
    }
}

package cn.xmx.ioc.lifecycle;

import java.lang.reflect.Proxy;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;


//后置处理器
public class NdBeanPostProcessor implements BeanPostProcessor {

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
       System.out.println("NdBeanPostProcessor 在"+beanName+"对象初始化之【前】调用......");
       if(beanName.equals("car")) {
           return   new CglibInterceptor().getIntance(bean.getClass());
       }
       return bean;
        
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("NdBeanPostProcessor 在"+beanName+"对象初始化之【后】调用......");
        return bean;
    }

}

package cn.xmx.ioc.lifecycle;

import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MainConfig {
    @Bean(name="car",initMethod="init",destroyMethod="destroy")
    public Car getCar() {
        return new Car("大黄蜂");
    }
    
    @Bean
    public BeanPostProcessor getBeanPostProcessor() {
        return new NdBeanPostProcessor();
    }
    @Bean
    public InstantiationAwareBeanPostProcessorAdapter getIns(){
        return new MyInstantiationAwareBeanPostProcessorAdapter();
    }
    
}

package cn.xmx.ioc.lifecycle;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/*
 四个主生命周期
         (1)实例化之前干预     InstantiationAwareBeanPostProcessorAdapter.postProcessBeforeInstantiation()
     1.实例化
          (2)实例化之后干预   InstantiationAwareBeanPostProcessorAdapter.postProcessAfterInstantiation()
     2.填充属性(给属性赋值)
     
          (1)初始化之前干预   BeanPostProcessor.postProcessBeforeInitialization()
     3.初始化化(比如准备资源文件)
             3) 属性进行干预  ----修改属性或属性值
     
         (2)初始化之后干预    BeanPostProcessor.postProcessAfterInitialization()
         
     4.销毁(释放资源---对象从内存销毁)
 N个接口
     1、干预多次
         1)BeanPostProcessor
     2、干预一次
         1)Aware
     
 */
public class TestLifeCycle {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
        Car car = (Car) context.getBean("car");
        System.out.println(car);//toString
        System.out.println("beanname:"+car.getBeanName());
        System.out.println("beanfactory:"+car.getBeanFactory());
        System.out.println("applicationContext:"+car.getApplicationContext());
    }
}

2.2 Interfaces appelées une seule fois

2.2.1 Interfaces liées à conscient:

  • BeanNameAware
  • BeanFactoryAware
  • ApplicationContextAware

La classe d'entité doit implémenter ces interfaces, appeler la méthode setBeanName () du Bean pour transmettre la valeur d'id du Bean actuel, appeler la méthode setBeanFactory () pour transmettre la référence de l'instance d'usine actuelle et appeler la méthode setApplicationContext () pour transmettre la référence de l'instance ApplicationContext actuelle.
Le code spécifique est indiqué ci-dessous:

package cn.xmx.ioc.lifecycle;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class Car implements BeanNameAware, BeanFactoryAware, ApplicationContextAware {
    private String  name;
    private String beanName;
    private BeanFactory beanFactory;
    private ApplicationContext applicationContext;
    public void init() {
        System.out.println("car 在初始化---加载资源");
        
    }
    
    public void destroy() {
        System.out.println("car 在销毁---释放资源");
    }
    
    
    
    public Car() {
        super();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Car(String name) {
        super();
        this.name = name;
        System.out.println("car实例化了");
    }


    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("beanFactory:"+beanFactory);
        this.beanFactory = beanFactory;
    }

    public BeanFactory getBeanFactory(){
        return this.beanFactory;
    }

    public void setBeanName(String s) {
        System.out.println("beanName:"+s);
        this.beanName = s ;
    }

    public String getBeanName() {
        return this.beanName;
    }

    public ApplicationContext getApplicationContext() {
        return this.applicationContext;
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("applicationContext:"+applicationContext);
        this.applicationContext = applicationContext;
    }
}

2.2.2 Deux interfaces de cycle de vie

Spring nous aide à faire l'instanciation et l'attribution d'attributs. Les deux étapes du cycle de vie que nous pouvons implémenter sont l'initialisation et la destruction.
1.InitializingBean correspond à la phase d'initialisation du cycle de vie, qui est appelée dans la méthode invokeInitMethods (beanName, wrappedBean, mbd); du code source.
2. DisposableBean est similaire à InitializingBean, correspondant à la phase de destruction du cycle de vie, avec la méthode ConfigurableApplicationContext # close () comme entrée. L'implémentation consiste à prendre tous les beans qui implémentent l'interface DisposableBean via une boucle, puis à appeler sa méthode destroy ().

3. Résumé

L'ensemble du processus d'exécution du cycle de vie Bean est décrit comme suit:

  1. Si vous créez une classe qui hérite de l'interface InstantiationAwareBeanPostProcessorAdapter et que vous configurez l'injection de cette classe dans le fichier de configuration, c'est-à-dire que l'InstantiationAwareBeanPostProcessorAdapter est associé au bean, Spring appellera la méthode postProcessBeforeInstantiation () de l'interface.
  2. Selon la configuration, appelez la méthode de construction Bean ou la méthode factory pour instancier le Bean.
  3. Si InstantiationAwareBeanPostProcessorAdapter est associé au bean, Spring appellera la méthode postProcessAfterInstantiation () de l'interface.
  4. Utilisez l'injection de dépendances pour terminer l'injection de configuration de toutes les valeurs d'attribut dans Bean.
  5. Si le Bean implémente l'interface BeanNameAware, Spring appelle la méthode setBeanName () du Bean pour transmettre la valeur id du Bean actuel.
  6. Si le Bean implémente l'interface BeanFactoryAware, Spring appelle la méthode setBeanFactory () pour transmettre la référence de l'instance d'usine actuelle.
  7. Si le Bean implémente l'interface ApplicationContextAware, Spring appelle la méthode setApplicationContext () pour transmettre une référence à l'instance ApplicationContext actuelle.
  8. Si le BeanPostProcessor est associé au Bean, Spring appellera la méthode de pré-initialisation postProcessBeforeInitialzation () de l'interface pour traiter le Bean. Ceci est très important ici, et l'AOP de Spring est implémenté en l'utilisant.
  9. Si le Bean implémente l'interface InitializingBean, Spring appellera la méthode afterPropertiesSet ().
  10. Si la méthode d'initialisation est spécifiée via l'attribut init-method dans le fichier de configuration, la méthode d'initialisation est appelée.
  11. Si le BeanPostProcessor est associé au Bean, Spring appellera la méthode d'initialisation de l'interface postProcessAfterInitialization ().
    Remarque: Une fois le travail ci-dessus terminé, le bean peut être appliqué plus tard. Le bean est un singleton, donc dans ce cas, nous appelons le bean avec le même id sera l'instance avec la même adresse de contenu, bien sûr, dans le fichier de configuration de spring Non-Singleton peut également être configuré dans.
  12. Si le Bean implémente l'interface DisposableBean, Spring appellera la méthode destroy () pour détruire le Bean dans Spring; si la méthode de destruction du Bean est spécifiée dans le fichier de configuration via l'attribut destruction-method, Spring appellera cette méthode pour détruire le Bean.

original

2. Questions d'entretien: la différence entre le DI de Spring et le CIO

1. Parlez de Spring IOC et DI, et de leur différence

IOC (Inversion of Control):

L'inversion de contrôle signifie qu'il n'est pas responsable de la création et de la maintenance des objets, et le droit de gérer la création des objets est inversé sur le conteneur Spring. Créé et maintenu par le conteneur Spring.

DI (injection de dépendance):

L'injection de dépendances est incarnée par deux classes ou plus, et les dépendances d'objet sont automatiquement transmises à l'objet cible (DI) pour la gestion, sans que l'objet acquière des dépendances par lui-même.

la différence:

  • IOC doit confier la création des objets au conteneur Spring (pour gérer le cycle de vie du bean)
  • DI s'appuie sur le conteneur IOC et est responsable de la mise en œuvre des dépendances et de la création d'objets, et n'a pas besoin d'être implémenté via

2. Interview: Qu'est-ce que l'IoC et quelle est la différence entre l'IoC et DI?

(1) L'IoC, également connu sous le nom d'inversion de contrôle, est une façon de penser, et son objectif principal est la création et la gestion d' objets Java . Par rapport à la méthode traditionnelle, lorsque nous avons besoin d'un objet, nous n'avons pas besoin d'en créer un directement, mais d'en obtenir un dans le conteneur Spring. À ce stade, nous perdons le contrôle de l'objet et ne conservons que le droit de l'utiliser. Mais cela peut également éliminer le besoin de se concentrer sur la gestion des objets.

(2) Le soi-disant contrôle fait référence aux droits des objets de gestion.

(3) Le soi-disant renversement fait référence à la gestion par Spring plutôt qu'au développeur.

(4) IoC L'un des objectifs est de découpler ensemble, lorsqu'un navire de gestion d'objets à un tiers, le couplage entre les objets de manière nouvelle par rapport aux diminutions conventionnelles. Dans le même temps, Spring IoC peut également réduire le coût de la gestion des objets , comme l' implémentation du mode singleton (la valeur par défaut est singleton) et ainsi de suite.

(5) Il convient de noter que la relation entre IoC et DI n'en est pas une, similaire à la différence entre les interfaces et les classes d'implémentation . IoC est une idée de conception, DI est une implémentation d'IoC , DI est également appelée injection de dépendances, dans Spring Vous pouvez injecter les objets dans le conteneur Spring à l'emplacement spécifié via l'annotation @Autowired.

[Note] Voici un résumé de nombreux points de connaissance, non pas à mémoriser par cœur, mais à faire un résumé inductif après avoir vraiment compris comment la couche inférieure de Spring est implémentée.

● La meilleure optimisation des performances Tomcat8 de l'histoire

Pourquoi Alibaba peut-il résister à 10 milliards en 90 secondes? - L'évolution de l'architecture distribuée à haute concurrence côté serveur

Plateforme de commerce électronique B2B - Fonction de paiement électronique ChinaPay UnionPay

Apprenez le verrouillage distribué de Zookeeper, laissez les enquêteurs vous regarder avec admiration

SpringCloud e-commerce spike microservice-solution de verrouillage distribué Redisson

Découvrez d'autres bons articles, entrez dans le compte officiel - s'il vous plaît moi - excellent dans le passé

Un compte public profond et émouvant 0.0

 

Je suppose que tu aimes

Origine blog.csdn.net/a1036645146/article/details/109483928
conseillé
Classement