Principe sous-jacent de la dépendance circulaire SpringIOC

faire référence à

qu'est-ce que la dépendance circulaire

En termes simples, l'objet A dépend de l'objet B et l'objet B dépend de l'objet A.

	// A依赖了B
	class A{
    
    
		public B b;
	} 

	// B依赖了A
	class B{
    
    
		public A a;
	}

Si vous ne considérez pas Spring, les dépendances circulaires ne sont pas un problème, car il est normal que les objets dépendent les uns des autres.

	A a = new A();
	B b = new B();

	a.b = b;
	b.a = a;

Donc A et B dépendent l'un de l'autre

Mais la dépendance circulaire est un problème dans Spring, car dans Spring, un objet n'est pas simplement nouveau, mais passera par une série de cycles de vie Bean, et c'est à cause du cycle de vie Bean que les dépendances circulaires apparaîtront en question. Bien sûr, dans Spring, il existe de nombreux scénarios de dépendances circulaires, certains scénarios que Spring résout automatiquement pour nous, et certains scénarios nécessitent des programmeurs pour être résolus.

Pour comprendre les dépendances circulaires dans Spring, vous devez d'abord comprendre le cycle de vie des beans dans Spring.

Processus de chargement des conteneurs IOC

Équivalent à la création de tous les beans singleton

  1. Lorsqu'un nouveau applicationContext est créé, le chargement du conteneur est exécuté et les informations de définition sont lues à partir de la configuration (< bean > @Component @Bean), chargées dans des objets BeanDefination individuels et stockées dans un BeanDefinationMap<String(BeanName), BeanDefination>
  2. Créez tous les BD de manière cyclique dans BeanFactory (responsable de la création de beans, mode de conception d'usine simple) et produisez des beans via la méthode getBean. Les étapes de création sont les suivantes
    1. Tout d'abord, allez dans le conteneur Bean (carte du cache de premier niveau) pour savoir si un objet Bean existe déjà, et revenez directement s'il est trouvé.
    2. S'il n'est pas trouvé, il commence à créer un bean :
      1. Instanciation : obtenir l'objet BD actuel, bd.getBeanClass().newInstance() pour obtenir l'objet instance (réflexion)
      2. DI d'injection d'attribut (@Autowired) : s'il existe une annotation @Autowired sur l'attribut de l'objet, le processus de création sera appelé de manière récursive.C'est pourquoi des dépendances circulaires se produisent
      3. Initialisation : rappelez la méthode d'initialisation, implémentez l'interface InitializingBean pour la personnalisation et implémentez la méthode afterPropertiesSet()
    3. Enfin, placez le Bean créé dans le cache de premier niveau (une Map) singletonObjects, et retournez

Résolution de dépendance circulaire

Étant donné que Spring appelle la méthode getBean de manière récursive lors de l'injection de propriété, cela peut entraîner un problème de dépendance circulaire. La solution est la suivante :

  1. Une fois l'instanciation terminée, l'objet Bean est directement ajouté au cache de premier niveau singletonObjects , mais cet objet est incomplet et plusieurs threads peuvent accéder à des beans incomplets.
  2. À cette fin, nous pouvons verrouiller le cache de premier niveau. Lorsque plusieurs threads y accèdent, il attend que le thread en cours génère un objet Bean complet, puis y accède. Cependant, certains beans sont complets et ne peuvent pas être obtenus par le thread , ce qui est très efficace.
  3. À cette fin, nous introduisons le cache de second niveau earlySingletonObjects , plaçons les objets incomplets dans le cache de second niveau et verrouillons le cache de second niveau, et les objets complets sont placés dans le cache de premier niveau, de sorte que l'efficacité est grandement améliorée ; (le cache de deuxième niveau est destiné à résoudre les dépendances circulaires et peut résoudre le problème de performances lié à l'obtention de bena complets en simultanéité)
  4. Cependant, si deux threads, le thread actuel s'exécute dans le cache de premier niveau et trouve qu'il n'y en a pas, un autre thread génère un bean complet et place le bean dans le cache de premier niveau. À ce moment, le thread actuel s'exécute dans le second niveau. cache et trouve qu'il n'y a pas , c'est-à-dire qu'il est considéré qu'il n'y a pas de cache à deux niveaux, et il choisira de le créer, ce qui n'est évidemment pas censé l'être, nous devons donc revérifier le verrou , que c'est-à-dire, vérifiez à nouveau si le cache de premier niveau contient le bean
  5. Normalement, le proxy dynamique AOP (implémenté par JDK et CGLIB) est exécuté après la création d'un objet. Spring choisit d'exécuter le proxy dynamique AOP lors de l'initialisation après l'attribution de l'attribut, ce qui crée un nouveau problème : A dépend de B et B dépend de A. Quand l'objet de A dont B dépend est incomplet, ce n'est pas un objet proxy dynamique.
  6. Par conséquent, les Beans ordinaires doivent être mandatés dynamiquement lors de l'initialisation, et les Beans qui génèrent des dépendances circulaires doivent générer des objets proxy dynamiques et les placer dans le cache de second niveau lorsque les attributs sont attribués, et enfin retirer l'objet proxy dynamique du cache de second niveau. . mettre en cache de premier niveau
  7. Spring exige un strict respect du cycle de vie du bean. Si tous les beans génèrent des objets proxy dynamiques après l'attribution des attributs, le cycle de vie est violé. Par conséquent, nous devons juger s'il existe une dépendance circulaire, c'est-à-dire que l'objet A doit être généré pour la deuxième fois, c'est-à-dire que s'il y a un objet A dans le cache de second niveau, nous générerons un proxy dynamique objet et placez-le dans le cache de second niveau.
  8. Cependant, un nouveau problème se pose. Lorsque A dépend cycliquement de B et C, deux objets proxy dynamiques sont générés ; afin de s'assurer qu'un seul objet proxy dynamique est créé, nous introduisons un cache à trois niveaux singletonFactories , c'est-à-dire le premier objet proxy dynamique sera généré. Placez-le dans le cache de troisième niveau, la prochaine fois, vérifiez s'il y a un objet proxy dynamique dans le cache de troisième niveau, et retournez s'il y en a

Résumé :
Cache de niveau 1 : pool singleton, qui contient tous les beans complets
Cache de niveau 2 : résout les problèmes de singleton et de performances des
dépendances circulaires Découplage, responsabilité unique

Je suppose que tu aimes

Origine blog.csdn.net/upset_poor/article/details/124059009
conseillé
Classement