Spring tiene su propia solución para dependencias circulares entre frijoles. El punto clave es el caché de nivel tres. Por supuesto, esta solución no puede resolver todos los problemas, solo puede resolver la dependencia circular de los no constructores en el modo singleton de frijoles.
Comenzaremos desde el orden de inicialización de A-> B-> Ca, lo que significa que se necesitan casos de B en el frijol de A, se necesitan casos de C en el frijol de B, se necesitan instancias de A en el frijol de C, y las instancias de A son necesarias en el frijol de C., por supuesto, esta necesidad no es una dependencia como el constructor. Una vez que los requisitos previos están disponibles, podemos comenzar. No hay duda de que inicializaremos lo primero. El método de inicialización es org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
protegido <t> t dogetBean (nombre de cadena final, clase final <t> requiredType, objeto final [] args, boolean typecheckonly) lanza Beansexception {String final beanName = transformedBeanName (name); Objeto frijol; // Consulte ansiosamente la caché de singleton para singletons registrados manualmente. Object SharedInstance = GetSingLeton (BeanName); // Focus 1 if (SharedInstance! = Null && args == null) {if (logger.isdeBugeNabled ()) {if (isSingLetIncurrentlyInCreation (beanName)) {logger.deBug ("que devuelve ansiosamente la instancia de Singleton Bean '" + BeanName + "eso no está completamente inicializado, una consecuencia de una consecuencia de una consecuencia de una consecuencia de una consecuencia ansiosa"); } else {logger.debug ("Devuelve la instancia en caché de Singleton Bean" + BeanName + "'"); }} bean = getObjectForBeanInstance (SharedInstance, Name, BeanName, NULL); } else {// fall si ya estamos creando esta instancia de Bean: // se asume dentro de una referencia circular. if (isProTotyPecurrentlyIncreation (beanName)) {tirar nueva beanCurrentlyIncreationException (beanName); } // Compruebe si la definición de frijol existe en esta fábrica. BeanFactory ParentBeanFactory = getParentBeanFactory (); if (parentBeanFactory! = null &&! ContinsBeanDefinition (beanName)) {// no encontrado -> Verifique el padre. Cadena nametolookup = originalBeanName (nombre); if (args! = null) {// delegación al padre con args explícitos. return (t) parentBeanFactory.getBean (nametolookup, args); } else {// no args -> delegado al método GetBean estándar. return parentBeanFactory.getBean (nametolookup, requiredType); }} if (! typecheckonly) {markbeanascreated (beanName); } try {final rootbeanDefinition mbd = getMergedLocalBeanDefinition (beanName); checkmergedBeanDefinition (MBD, BeanName, Args); // Garantizar la inicialización de los frijoles de los que depende el frijol actual. String [] dependson = mbd.getdependson (); if (dependentson! = null) {for (string dependsonBean: dependson) {if (isDependent (beanName, dependSonBean)) {throL New BeanCreationException (mbd.getResourceDescription (), beanName, "Circular depende de la relación entre '" + beanname + "y" + "depender + +" ");); } RegistroDependentBean (DependentSonBean, BeanName); getBean (dependientes en suBean); }} // Crear instancia de Bean. if (mbd.issingleton ()) {// preocupación 2 sharedInstance = getSingLeton (beanName, new ObjectFactory <SPET> () {@Override Public Object getObject () lanza BeanseException {try {return createBean (beanName, mbd, args);} Catch (beansexception ex) {// explicitly instancia de la instancia de singleton. Ante el proceso de creación, para permitir la resolución de referencia circular. bean = getObjectForBeanInstance (SharedInstance, Name, BeanName, MBD); } else if (mbd.Isprototype ()) {// Es un prototipo -> Crear una nueva instancia. Objeto prototypeInstance = null; intente {antes de la creación de behyprototypreation (beanName); PrototypeInstance = createBean (BeanName, MBD, Args); } Finalmente {AfterPrototyPecReation (BeanName); } bean = getObjectForBeanInstance (prototypeInstance, nombre, beanName, mbd); } else {string scopeName = mbd.getscope (); alcance final alcance = this.scopes.get (Scopename); if (scope == null) {lanzar nueva ilegalstateException ("no hay alcance registrado para el nombre del alcance '" + scopeName + "'"); } try {object scopedInstance = scope.get (beanName, new ObjectFactory <Sect> () {@Override Public Object getObject () lanza BeanseException {antes de antes de la placa (beanName); intente {return createBean (beanName, mbd, args);} finalmente {después bean = getObjectForBeanInstance (ScopedInstance, Name, BeanName, MBD); } Catch (ilegalStateException ex) {Throw New BeanCreationException (BeanName, "Scope" " + ScopeName +" 'no está activo para el hilo actual; considere " +" definiendo un proxy alcanzado para este bean si tiene la intención de referirse a él desde un singleton ", ex); }}} Catch (Beansexception ex) {CleanupafeRBeatCreationFailure (BeanName); tirar ex; }} // Verifique si el tipo requerido coincide con el tipo de la instancia de Bean real. if (requiredType! = null && bean! = null &&! requireType.isassignableFrom (bean.getClass ())) {try {return getTypeConverter (). ConvertifNeceSary (bean, requiredType); } catch (typemismatchException ex) {if (logger.isDebugeNabled ()) {logger.deBug ("Falling to convertir ' + name +"' al tipo requerido [" + classUtilss.getQualifiedName (requiredType) +"] ", ex); } tirar new BeanNotOfRequiredTypeException (nombre, requiredType, bean.getClass ()); }} return (t) bean; } Este método es muy largo, hablemos de ello poco a poco. Veamos nuestro enfoque primero. Object sharedInstance = getSingleton(beanName ) obtiene un objeto Singleton de la colección de singletons basados en el nombre. Veamos este método, y finalmente es org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
Objeto protegido GetSingLeton (String BeanName, boolean loodearlyReference) {Object SingLetOnObject = this.singletOnObjects.get (BeanName); if (singletOnObject == null && issingletOncurrentlyCreation (beanName)) {SynChronized (this.singletOnObjects) {SingletOnObject = this.earlysingletOnObjects.get (beanName); if (singletOnObject == null && loodearlyReference) {ObjectFactory <?> SingletOnFactory = this.singletAnfactory.get (beanName); if (singletonfactory! = null) {singletOnObject = singletOnFactory.getObject (); this.arlysingletOnObjects.put (BeanName, SingletOnObject); this.singletonFactory.remove (BeanName); }}} return (singletOnObject! = null_object? singletOnObject: null); } Todos deben prestar atención a este método, es muy importante. Mencionamos el caché de nivel 3 al principio, y uno de los puntos de uso está aquí. ¿Qué caché de nivel 3 es? singletonObjects del caché de primer nivel se coloca con SingletOnObjects instanciados. El segundo nivel earlySingletonObjects almacena objetos singleton que están expuestos de antemano (no completamente ensamblados). Las factores singleton de tercer nivel almacenan la fábrica de objetos del objeto que se instancia. Después de explicar el caché de nivel 3, echemos un vistazo a la lógica. La primera vez que vengo en this.singletonObjects.get(beanName) Devuelve NULL. Luego, isSingletonCurrentlyInCreation determina si los datos se pueden obtener en el caché secundario.
Public boolean issingletEncurrentlyRceation (string beanName) {return this.singletonscurrentlyincreation.contains (beanName); } ¿Se incluye el nombre de la frijoles en el conjunto de sincratación singletonsCurrentlyInCreation que contiene el nombre de frijoles entrante? No hay lugar para configurarlo antes, por lo que definitivamente no lo incluye. Por lo tanto, este método devuelve falso, y el proceso posterior no se dejará. El método getSingleton devuelve nulo.
Veamos el Focus 2. También es un getSingleton , pero es el proceso real de crear un frijol. Podemos ver que se pasa un objeto anónimo de Factory. El método GetObject llamado CreateBean, el método real para crear un frijol. Por supuesto, podemos dejarlo a un lado y continuar mirando nuestro método getSingleton
Public Object GetSingLeton (String BeanName, ObjectFactory <?> SingletonFactory) {Afirert.NotNull (BeanName, "'BeanName' no debe ser nulo"); sincronizado (this.singletOnObjects) {object singletOnObject = this.singletOnObjects.get (beanName); if (singletOnObject == null) {if (this.singletonscurrently Indestruction) {Throw New BeanCreationNotalloweDException (BeanName, "Singleton Bean Creation no permitido mientras que los singletons de esta fábrica están en destrucción" + "(¡no solicite un frijol de una fábrica de frijoles en una implementación de método de destrucción!)");; } if (logger.isDebugeNabled ()) {logger.debug ("Creación de instancia compartida de Singleton Bean" + BeanName + "'"); } befefefefefefefefefefEntletRceation (BeanName); boolean Newsingleton = falso; Boolean RecordsUpepressedExceptions = (this.supressedExceptions == null); if (RecordsupressedExceptions) {this.supressedExceptions = new LinkedHashSet <CECESION> (); } try {singletOnObject = singletOnFactory.getObject (); NewsingLeton = True; } Catch (ilegalStateException ex) {// El objeto Singleton apareció implícitamente mientras tanto -> // En caso afirmativo, continúe con él ya que la excepción indica ese estado. singletOnObject = this.singletOnObjects.get (beanName); if (singletOnObject == null) {lanzar ex; }} Catch (BeanCreationException ex) {if (RecordsupressedExceptions) {for (excepción supressedException: this.supressedExceptions) {ex.addrelatedCause (supressedException); }} tirar ex; } Finalmente {if (RecordSupressedExceptions) {this.supressedExceptions = null; } AfterSingletonCreation (BeanName); } if (NewsingLeton) {AddSingleton (BeanName, SingletOnObject); }} return (singletOnObject! = null_object? singletOnObject: null); }} La primera oración de este método Object singletonObject = this.singletonObjects.get(beanName) obtiene datos del caché de primer nivel, que definitivamente es nulo. Luego se llama al método beforeSingletonCreation .
Protegido nulo BefefefefefefefefefefEltletReation (String BeanName) {if (! this.increationCheckExClusions.contains (beanName) &&! this.singletonscurrentlyIncreation.add (beanName)) {tirar nueva beanCreationionException (beanName); }} Entre ellos se encuentra el proceso de agregar BeanName al conjunto de singletonsCurrentlyInCreation . Este conjunto es muy importante y se usará más tarde. Luego, llame al método GetObject de SingletOnFactory para realizar el proceso de creación real. Echemos un vistazo al proceso de creación real mencionado anteriormente createBean La lógica central en su interior es doCreateBean .
Objeto protegido DoCreateBean (String BeanName final, Final RootBeanDefinition MBD, objeto final [] args) {// Instanciar el bean. Beanwrapper instancewrapper = null; if (mbd.issingleton ()) {instancewrapper = this.FactoryBeanInstancecache.remove (beanName); } if (instancewrapper == null) {instancewrapper = createBeanInstance (beanName, mbd, args); } final de objeto final = (instancewrapper! = null? instancewrapper.getwrappedInstance (): null); Clase <?> BeanType = (instancewrapper! = Null? Instancewrapper.getwrappedClass (): null); // Permitir que los postprocesadores modifiquen la definición de frijol fusionado. sincronizado (mbd.postprocessinglock) {if (! mbd.postprocessed) {applymergedBeanDefinitionPostProcessors (MBD, beanType, beanName); mbd.postprocessed = true; }} // Cache Singletons para poder resolver referencias circulares // incluso cuando se activan por interfaces de ciclo de vida como BeanFactoryaware. // preocupación3 boolean EarlySingletElExPoure = (mbd.issingleton () && this. allowcircularReferences && issingletEncurrentlyRcreation (beanName)); if (EarlySingletOnExPoure) {if (logger.isdeBugeNabled ()) {logger.debug ("" frijol caché ansiosamente " + beanName +" 'para permitir la resolución de posibles referencias circulares "); } addSingLetOnFactory (BeanName, New ObjectFactory <ject> () {@Override Public Object getObject () lanza BeanSException {return getEarreArlyBeanReference (beanName, mbd, bean);}}); } // Inicializa la instancia de Bean. Objeto exposedobject = bean; intente {PopulateBean (BeanName, MBD, InstanceWrapper); if (exposedObject! = null) {exposedObject = inicializeBean (beanName, exposedObject, mbd); }} Catch (Showable Ex) {if (ex instanceof BeanCreationException && beanName.equals ((((((( } else {Throw New BeanCreationException (mbd.getResourceDescription (), BeanName, "Inicialización de Bean falló", ex); }} if (EarlySingletOnExPosure) {Object EarlySingletonReference = GetSingLeton (BeanName, False); if (EarlySingletOnreference! = NULL) {if (exposedObject == bean) {exposedObject = EarlySingletOnreference; } else if (! this. allowrawinjectionDespitewrapping && hasDependentBean (beanName)) {string [] dependentBeans = getDependentBeans (beanName); Establecer <String> RealDependentBeans = new LinkedHashset <String> (dependenceBeans.length); para (String DependentBeans: DependentBeans) {if (! RemoveSingLetOnifCreateDfortyPeCheckonly (dependiente)) {RealDependentBeans.add (dependiente); }} if (! RealDependentBeanS.IsEmpty ()) {arrojar nuevo beanCurrentlyIncreationionionImception (BeanName, "Bean con el nombre '" + BeanName + "' se ha inyectado en otras frijoles [" + StringUtils.CollectionToComMadelimiteString (RealDependentBeans) + "] en su versión RAW como parte de una referencia circular, pero ha sido la referencia circular, pero ha sido la referencia circular, pero ha sido" ha sido ". Otros frijoles no usan la versión final del bean " +". }}}}} // Registre el frijol como desechable. Pruebe {RegistroDiscoSableBeanifnecessary (BeanName, Bean, MBD); } Catch (beandefinitionValidationException ex) {tire nueva beancreationException (mbd.getResourcedescription (), beanName, "firma de destrucción inválida", ex); } return exposedObject; } createBeanInstance crea un objeto usando reflexión. Echemos un vistazo al valor de atributo de Jueces 3 earlySingletonExposure . Uno de los puntos de juicio isSingletonCurrentlyInCreation(beanName)
Public boolean issingletEncurrentlyRceation (string beanName) {return this.singletonscurrentlyincreation.contains (beanName); } Descubrí que se utiliza el conjunto de SingletonscurrentlyIncreation. El nombre de la frijoles se ha completado en los pasos anteriores, por lo que se puede encontrar. Por lo tanto, se determina que la propiedad earlySingletonExposure es cierta en combinación con otras condiciones, y el siguiente proceso se agrega addSingletonFactory . Aquí hay una fábrica de objetos correspondiente al nombre de bean (a). La implementación de su método GetObject se logra a través getEarlyBeanReference . Primero, echemos un vistazo a la implementación de AddSingletOnFactory
void protegido addsingletOnFactory (String BeanName, ObjectFactory <?> SingletonFactory) {Afirert.NotNull (SingletOnFactory, "Singleton Factory no debe ser nulo"); sincronizado (this.singletOnObjects) {if (! this.singletOnObjects.containskey (beanName)) {this.singletonfactory.put (beanName, singletAnfactory); this.arlysingletOnObjects.remove (BeanName); this.RegisteredSingletons.add (BeanName); }}} Almacenamiento de datos a los fábricas de cache de tercer nivel, borrando los datos de caché de segundo nivel basados en BeanName. Aquí hay un punto muy importante, que es establecer el valor en el caché de tercer nivel, que es el punto central del procesamiento de dependencias circulares de Spring. El método getEarlyBeanReference es una implementación de GetObject. Simplemente se puede considerar que devuelve una instancia de objeto que se llena con A. Después de configurar el caché de nivel 3, comienza el proceso de llenar las propiedades del objeto A. La siguiente descripción no tiene indicaciones del código fuente, solo una breve introducción.
Al llenar A, descubrí que se necesita un frijol tipo B, por lo que seguí llamando al método GetBean para crearlo. El proceso de memoria es exactamente el mismo que un anterior. Luego fui al proceso de llenar un frijol tipo C. La misma llamada GetBean (c) para ejecutar. Al llenar una propiedad A, llamé a GetBean (a). Continuemos desde aquí que llamé Object sharedInstance = getSingleton(beanName), el mismo código, pero la lógica de procesamiento es completamente diferente.
Objeto protegido GetSingLeton (String BeanName, boolean loodearlyReference) {Object SingLetOnObject = this.singletOnObjects.get (BeanName); if (singletOnObject == null && issingletOncurrentlyCreation (beanName)) {SynChronized (this.singletOnObjects) {SingletOnObject = this.earlysingletOnObjects.get (beanName); if (singletOnObject == null && loodearlyReference) {ObjectFactory <?> SingletOnFactory = this.singletAnfactory.get (beanName); if (singletonfactory! = null) {singletOnObject = singletOnFactory.getObject (); this.arlysingletOnObjects.put (BeanName, SingletOnObject); this.singletonFactory.remove (BeanName); }}} return (singletOnObject! = null_object? singletOnObject: null); } Aún así, el objeto se obtiene de SingletOnObjects no se puede obtener. Debido a que A está en el set singletonsCurrentlyInCreation , ingresa a la siguiente lógica y la toma de los Cache earlySingletonObjects de segundo nivel, pero aún no se ha encontrado. Luego encuentra la fábrica de objetos correspondiente de las singletonFactories Llame getObject para obtener el objeto de instancia de A que no se ha llenado por completo, y luego elimina los datos de caché de tercer nivel, llena los datos de caché de segundo nivel y devuelve este objeto A. C depende del relleno de instancia de A, aunque esto está incompleto. No importa cómo se complete el relleno de estilo C, puede colocar C en los singletonObjects de caché de primer nivel y limpiar los datos de los cachés de segundo nivel y tercer nivel al mismo tiempo. En el mismo proceso, si C depende de B, se llena B. Del mismo modo, si B depende de A se llena, A se llena. Así es como Spring resuelve referencias circulares.
Lo anterior es todo el contenido de este artículo. Espero que sea útil para el aprendizaje de todos y espero que todos apoyen más a Wulin.com.