Le printemps a sa propre solution pour les dépendances circulaires entre les haricots. Le point clé est le cache de niveau trois. Bien sûr, cette solution ne peut pas résoudre tous les problèmes, il ne peut résoudre que la dépendance circulaire des non-constructions en mode Saning Singleton.
Nous commencerons de l'ordre d'initialisation de A-> B-> CA, ce qui signifie que des cas de B sont nécessaires dans le haricot de A, des instances de C sont nécessaires dans le haricot de B, les cas de A sont nécessaires dans le haricot de C, et les cas de A sont nécessaires dans le haricot de C. Bien sûr, ce besoin n'est pas une dépendance comme le constructeur. Une fois les conditions préalables disponibles, nous pouvons commencer. Il ne fait aucun doute que nous initialiserons un premier. La méthode d'initialisation est org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
protégé <T> T doGetBean (Nom de la chaîne finale, classe finale <T> requiredType, objet final [] args, boolean typECheckOnly) lève BeanSexception {final string beanname = transformEdBeAnName (name); Haricot d'objet; // Vérifiez avec impatience le cache singleton pour les singletons enregistrés manuellement. Objet SharedInstance = GetSingleton (beanname); // focus 1 if (sharedInstance! = Null && args == null) {if (logger.isdebugeNable ()) {if (issingletamCurrentelyIncreation (beanname)) {logger.debug ("Retour avec impatience avec impatience de Singleton Bean '" + haricot + "' qui n'est pas entièrement initialisé pourtant - une conséquence du circulaire"); } else {Logger.debug ("Renvoi d'instance mise en cache de Singleton Bean '" + Beanname + "'"); }} bean = getObjectForBeanInstance (SharedInstance, Name, Beanname, Null); } else {// échouer si nous créons déjà cette instance de bean: // nous sommes supposés dans une référence circulaire. if (isPrototyPyTyCurrentlyInCreation (beanname)) {lancez new BeanCurrentlyInCreationException (beanname); } // Vérifiez si la définition du bean existe dans cette usine. Beanfactory parentBeanFactory = getParentBeanFactory (); if (parentBeanFactory! = null &&! ContintainBeAndeFinition (beanname)) {// non trouvé -> Vérifiez le parent. String nametOlookup = originalBeanName (name); if (args! = null) {// Délégation à parent avec des args explicites. return (t) parentBeanfactory.getBean (nametolookup, args); } else {// no args -> déléguer à la méthode GetBean standard. return parentBeanFactory.getBean (nametolookup, requiredType); }} if (! typeCheckonly) {MarkBeAnascreated (beanname); } essayez {final rootBeAndefinition mbd = getMergedLocalBeAnDefinition (beanname); CheckmergedBeAnDefinition (MBD, Beanname, Args); // Garantir l'initialisation des haricots dont dépend le haricot actuel. String [] DependSon = MBD.GetDependSon (); if (Deeepntson! = null) {for (String DelateSonBean: DependSon) {if (isDependent (beanname, DependSonBean)) {Throw New BeanCreationException (Mbd.getResourceDeScription (), Beanname, "Circular Depend-on Relating" + Beanname + "'et' + DepenSonBean +" "" "); } RegisterDependentBean (DeeentsonBean, Beanname); getBean (DeeentsonBean); }} // Créer une instance de bean. if (mbd.issingleton ())) {// Concern 2 SharedInstance = GettingLeton (beanname, new objectFactory <objet> () {@Override public objet getObject () lance BeanSexception {Try {return CreateBean (beanname, mbd, args);} Catch (handsexception ex) {// Explicit retient l'instance de Singleton CACHE: It a été exprimé otant // avec impatience par le processus de création, pour permettre une résolution de référence circulaire. bean = getObjectForBeanInstance (SharedInstance, Name, Beanname, MBD); } else if (mbd.isprototype ()) {// c'est un prototype -> créer une nouvelle instance. Object PrototypeInSance = NULL; essayez {avantprototypeCreation (beanname); PrototypeInSance = CreateBean (beanname, mbd, args); } enfin {AfterPrototyPeCreation (beanname); } bean = getObjectForBeanInstance (prototypeInstance, nom, beanname, mbd); } else {String scopename = mbd.getScope (); Scope finale Scope = this.scopes.get (scopename); if (scope == null) {lancez new illégalStateException ("Aucune étendue enregistrée pour le nom de la lunette '" + scopename + "'"); } essayez {objet ScopedInstance = Scope.get (Beanname, New ObjectFactory <Bject> () {@Override public Object GetObject () lève BeanSexception {avantprotypeCreation (Beanname); Try {return CreateBean (Beanname, Mbd, Args);} enfin {afterProtyPeCreatation (beanname);}); bean = getObjectForBeanInstance (ScopedInstance, nom, beanname, MBD); } catch (illégalStateException ex) {Throw New BeanCreationException (Beanname, "Scope '" + Scopename + "' n'est pas actif pour le thread actuel; considérer" + "définir un proxy lune }}} catch (beanSexception ex) {CleanUpafterBeanCreationFailure (beanname); jeter ex; }} // Vérifiez si le type requis correspond au type de l'instance de bean réelle. if (requiredType! = null && bean! = null &&! requiredType.isAssignableFrom (bean.getClass ())) {try {return getTypeConverter (). ConvertifneceSsary (bean, requiredType); } catch (tymismatchException ex) {if (logger.isdebugeNable ()) {logger.debug ("n'a pas réussi à convertir bean '" + name + "' à type requis [" + classutils.getqualifiedName (requiretype) + "]", ex); } Jetez un nouveau beannotofrequiredTypeException (nom, requiredType, bean.getClass ()); }} return (t) bean; } Cette méthode est très longue, parlons-en petit à petit. Regardons d'abord notre concentration. Object sharedInstance = getSingleton(beanName ) obtient un objet singleton de la collection de singletons en fonction du nom. Regardons cette méthode, et c'est enfin org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
Objet protégé GettingLeton (String beanname, booléen intearlyreference) {objet singletonObject = this.SingletonObjects.get (beanname); if (singletonObject == null && issingletOrnilyInCreation (beanname)) {synchronisé (this.SingletOnObjects) {singletonObject = this.earlysingletonObjects.get (beanname); if (singletonObject == null && altearlyReference) {objectFactory <?> singletonfactory = this.Singletonfactory.get (beanname); if (singletonfactory! = null) {singletonObject = singletonfactory.getObject (); this.earlysingletonobjects.put (beanname, singletonObject); this.singletonfactory.reMove (beanname); }}} return (singletonObject! = null_object? singletonObject: null); } Tout le monde doit faire attention à cette méthode, c'est très important. Nous avons mentionné le cache de niveau 3 au début, et l'un des points d'utilisation est ici. De quel cache de niveau 3 s'agit-il? singletonObjects du premier cache de niveau sont placés avec des singletonobjects instanciés. Le deuxième niveau earlySingletonObjects stockait des objets singleton qui sont exposés à l'avance (non entièrement assemblés). Les singletonfactories de troisième niveau stockent l'usine d'objets de l'objet à instanciation. Après avoir expliqué le cache de niveau 3, jetons un coup d'œil à la logique. La première fois que je viens dans this.singletonObjects.get(beanName) renvoie null. Ensuite, isSingletonCurrentlyInCreation détermine si les données peuvent être obtenues dans le cache secondaire.
Boolean public IssingletToncurrentlyInCreation (string beanname) {return this.SingletOncurrentlyInCreation.Contains (beanname); } Le nom de haricot est-il inclus dans l'ensemble singletonsCurrentlyInCreation la création contienne-t-il le nom de haricot entrant? Il n'y a aucun endroit pour le régler avant, donc il ne l'inclut certainement pas. Par conséquent, cette méthode renvoie faux et le processus ultérieur ne sera pas laissé. La méthode getSingleton renvoie null.
Regardons le focus 2. C'est aussi un getSingleton , mais c'est le véritable processus de création d'un haricot. Nous pouvons voir qu'un objet ObjectFactory anonyme est passé. Bien sûr, nous pouvons le mettre de côté et continuer à regarder notre méthode getSingleton
Objet public getingLeTon (string beanname, objectFactory <?> singletonfactory) {assert.notnull (beanname, "'beanname' ne doit pas être nul"); synchronisé (this.singletonObjects) {objet singletonObject = this.singletonObjects.get (beanname); if (singletonObject == null) {if (this.singletonsonydentelyindestration) {lancez new BeanCreationNotallowEdException (Beanname, "la création de bean singleton n'est pas autorisée tandis que les singletons de cette usine sont en destruction" + "(ne pas demander un Bean d'un haricot dans une mise en œuvre de la méthode de destruction!)"); } if (logger.isdebugeNable ()) {logger.debug ("Création d'une instance partagée de singleton bean '" + beanname + "'"); } beforesingletonCreation (beanname); booléen newingleton = false; Boolean RecordsuPressedExceptions = (this.SuppressExceptions == null); if (enregistredUppressExceptions) {this.SuppressExceptions = new LinkedHashSet <exception> (); } essayez {singletonObject = singletonfactory.getObject (); Newingleton = true; } Catch (illégalStateException ex) {// L'objet Singleton est-il implicitement apparu en attendant -> // Si oui, procédez avec lui car l'exception indique cet état. singletonObject = this.singletonObjects.get (beanname); if (singletonObject == null) {throw ex; }} catch (beanCreationException ex) {if (enregistreduppressExceptions) {for (exception supprimedException: this.supprespripRedExceptions) {ex.AdDrelatedCause (supprimedException); }} Throw ex; } Enfin {if (enregistreduppressExceptions) {this.suppresprié lesceptions = null; } AfternsingletOnCreation (beanname); } if (Newingleton) {AddSingleton (beanname, singletonObject); }} return (singletonObject! = null_object? singletonObject: null); }} La première phrase de cette méthode Object singletonObject = this.singletonObjects.get(beanName) récupére les données du cache de premier niveau, qui est définitivement nul. La méthode beforeSingletonCreation est alors appelée.
Protected void beforeSingletOncreation (string beanname) {if (! this.increationchecKExclusions.contains (beanname) &&! this.singletonscurrentlyInCreation.add (beanname)) {lancez new BeancurrentelyInCreationException (BeanName); }} Parmi eux, il y a le processus d'ajout de name à l'ensemble singletonsCurrentlyInCreation réception. Cet ensemble est très important et sera utilisé plus tard. Ensuite, appelez la méthode GetObject de SingletonFactory pour effectuer le processus de création réel. Jetons un coup d'œil au processus de création réel mentionné ci-dessus createBean La logique de base à l'intérieur est doCreateBean .
Objet protégé DOCreateBean (Final String Beanname, Final RootBeAndefinition MBD, objet final [] Args) {// Instancier le bean. Beanwrapper instancewrapper = null; if (mbd.issingleton ()) {instanceWrapper = this.factoryBeanInStanceCache.Remove (beanname); } if (instanceWrapper == null) {instanceWrapper = CreateBeAnstance (beanname, mbd, args); } final objet bean = (instanceWrapper! = null? instancewrapper.getWrapyInSance (): null); Class <?> BeanType = (instanceWrapper! = Null? InstanceWrapper.getWrapyClass (): null); // Permettez aux post-processeurs de modifier la définition du bean fusionné. Synchronized (MBD.PostProcessingLock) {if (! MBD.PostProcessed) {ApplyMergedBeAnDeFinitionPostProcessors (MBD, beanType, Beanname); mbd.PostProcessed = true; }} // cache des singletons avec impatience pour pouvoir résoudre les références circulaires // même lorsqu'elles sont déclenchées par des interfaces de cycle de vie comme BeanfactoryAware. // Concern3 booléen EarlySingletOnExpose = (Mbd.issingleton () && this.AllowcircularReferences && iSingletOrNurrentlyInCreation (Beanname)); if (EarlySingletOnExpose) {if (logger.isdebugeNable ()) {logger.debug ("haricot empressément mis en cache '" + beanname + "' pour permettre de résoudre les références circulaires potentielles"); } AddSingLeTOnfactory (beanname, nouveau objetFactory <Bject> () {@Override public objet getObject () lève BeanSexception {return GetEarLyBeAnReference (beanname, mbd, bean);}}); } // Initialisez l'instance de bean. Objet exposéObject = Bean; essayez {populateBean (beanname, mbd, instancewrapper); if (exposéObject! = null) {exposéObject = initializeBean (beanname, exposéObject, mbd); }} catch (Throwable ex) {if (ex instanceof beanCreationException && beanname.equals (((beanCreationException) ex) .getBeAnName ())) {thord (beanCreationException) ex; } else {Throw new BeanCreationException (MBD.GetResourcedEcriScription (), beanname, "L'initialisation de la haricot a échoué", ex); }} if (EarlySingletOnExpose) {objet EarlySingletOnReference = GetSingleton (beanname, false); if (EarlySingLetOnReference! = null) {if (exposéObject == bean) {exposéObject = EarlySingletOnReference; } else if (! this.allowrawinjectionDesshipiteWapping && HasdependentBean (beanname)) {String [] DependentBeans = GetDependentBeans (beanname); Set <string> réelDependentBeans = new LinkedHashSet <string> (DependentBeans.Length); pour (String DependentBean: DependentBeans) {if (! RemoeSingletOnifreatedFortyPyCheckonly (DependentBean)) {réelDependentBeans.Add (DependentBean); }} if (! réelDependentBeans.Isempty ()) {Jetez un nouveau beancurrentelyInCreationException (beanname, "Bean avec nom '" + beanname + "' a été injecté dans d'autres haricots [" + stringUtils.CollectionTocomadielimitedString (réel. dit que d'autres haricots n'utilisent pas la version finale du haricot "+". }}}}} // Enregistrer le bean comme jetable. essayez {registerDisposableBeAnifnessary (beanname, bean, mbd); } catch (beanDefinitionValidationException ex) {Throw new BeanCreationException (mbd.getResourceDeScription (), beanname, "signature de destruction invalide", ex); } return exposéObject; } createBeanInstance crée un objet utilisant la réflexion. Jetons un coup d'œil à la valeur d'attribut du point de jugement 3 earlySingletonExposure . L'un des points de jugement isSingletonCurrentlyInCreation(beanName)
Boolean public IssingletToncurrentlyInCreation (string beanname) {return this.SingletOncurrentlyInCreation.Contains (beanname); } J'ai trouvé que l'ensemble Singletonsoncurremment à la crèche est utilisé. Le nom de haricot a été rempli par les étapes ci-dessus, il peut donc être trouvée. Par conséquent, la propriété earlySingletonExposure est déterminée comme étant vraie en combinaison avec d'autres conditions, et le processus suivant est ajouté addSingletonFactory . Voici une usine d'objets correspondant au nom de haricot (a). La mise en œuvre de sa méthode GetObject est réalisée via getEarlyBeanReference . Tout d'abord, jetons un coup d'œil à la mise en œuvre d'AddSingletOnfactory
Protected void AddSingletOnfactory (String beanname, objectFactory <?> singletonfactory) {assert.notnull (singletonfactory, "Singleton Factory ne doit pas être null"); synchronisé (this.singletonObjects) {if (! this.singletonobjects.containsKey (beanname)) {this.singletonfactory.put (beanname, singletonfactory); this.arlysingletonobject.remove (beanname); this.gisteredSingletons.Add (beanname); }}} Stockage des données vers le troisième niveau SingletOnfactories de cache, effacer les données de cache de deuxième niveau basées sur le nom de beanname. Il y a un point très important ici, qui est de définir la valeur dans le cache de troisième niveau, qui est le point central du traitement des dépendances circulaires par le printemps. La méthode getEarlyBeanReference est une implémentation de GetObject. Il peut être simplement considéré qu'il renvoie une instance d'objet qui est remplie de A. Après avoir réglé le cache de niveau 3, le processus de remplissage des propriétés de l'objet A commence. La description suivante n'a pas d'invites de code source, juste une brève introduction.
Lors du remplissage A, j'ai trouvé qu'un bean de type B est nécessaire, j'ai donc continué à appeler la méthode GetBean pour le créer. Le processus de mémoire est exactement le même que ce qui précède. Ensuite, je suis allé au processus de remplissage d'un haricot de type C, et le même appel getbean (c) est appelé à exécuter. Lors du remplissage d'une propriété A, j'ai appelé Getbean (A). Continuons à partir d'ici que j'ai appelé Object sharedInstance = getSingleton(beanName), le même code, mais la logique de traitement est complètement différente.
Objet protégé GettingLeton (String beanname, booléen intearlyreference) {objet singletonObject = this.SingletonObjects.get (beanname); if (singletonObject == null && issingletOrnilyInCreation (beanname)) {synchronisé (this.SingletOnObjects) {singletonObject = this.earlysingletonObjects.get (beanname); if (singletonObject == null && altearlyReference) {objectFactory <?> singletonfactory = this.Singletonfactory.get (beanname); if (singletonfactory! = null) {singletonObject = singletonfactory.getObject (); this.earlysingletonobjects.put (beanname, singletonObject); this.singletonfactory.reMove (beanname); }}} return (singletonObject! = null_object? singletonObject: null); } Pourtant, l'objet est obtenu à partir de singletonobjects ne peut pas être obtenu. Parce que A est dans l'ensemble singletonsCurrentlyInCreation , il entre dans la logique suivante et le tire du cache de deuxième niveau earlySingletonObjects , mais n'a toujours pas été trouvé. Ensuite, il trouve l'usine d'objets correspondante à partir des singletonFactories Appelez getObject pour obtenir l'objet d'instance de A qui n'a pas été complètement rempli, puis supprime les données de cache de troisième niveau, remplit les données de cache de deuxième niveau et renvoie cet objet A. C dépend du remplissage d'instance de A, bien que cela soit incomplet. Peu importe comment le remplissage de style C est terminé, vous pouvez mettre C dans les singletonObjects de premier niveau et nettoyer les données des caches de deuxième niveau et de troisième niveau en même temps. Dans le même processus, si C dépend de B est rempli, B est rempli. De même, si B dépend de A est rempli, A est rempli. C'est ainsi que le printemps résout les références circulaires.
Ce qui précède est tout le contenu de cet article. J'espère que cela sera utile à l'apprentissage de tous et j'espère que tout le monde soutiendra davantage Wulin.com.