A primavera tem sua própria solução para dependências circulares entre feijões. O ponto -chave é o nível três do cache. Obviamente, essa solução não pode resolver todos os problemas, só pode resolver a dependência circular de não construtores no modo de feijão singleton.
Começaremos a partir da ordem de inicialização de A-> B-> Ca, o que significa que são necessários casos de B no feijão de A, são necessários casos de C no feijão de B, os casos de A são necessários no feijão de C e os casos de A são necessários no feijão de C. É claro que essa necessidade não é dependente como construtor. Depois que os pré -requisitos estiverem disponíveis, podemos começar. Não há dúvida de que inicializaremos um primeiro. O método de inicialização é org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
Protegido <T> t DogetBean (nome da string final, classe final <T> requerirtype, objeto final [] args, boolean typecheckonly) lança beansexception {final string beanname = transformedbeanname (nome); Objeto Bean; // Verifica ansiosamente o singleton cache quanto a singletons registrados manualmente. Objeto compartilhadoInstance = Getingleton (nome Beanname); // foco 1 if (sharedInstance! = Null && args == null) {if (logger.isdebugenabled ()) {if (isingletoNcurrentlyinCreation (beanname)) {Logger.debug ("Retornando a instância e o cache de singleton bean '" + benname } else {Logger.debug ("Retornando a instância em cache de singleton bean '" + beanname + "'"); }} bean = getObjectForBeanInstance (SharedInstance, Nome, Beanname, NULL); } else {// falha se já estivermos criando esta instância do feijão: // somos assumidos em uma referência circular. if (isPrototyPeCurrentlyinCreation (Beanname)) {lança o novo beanscurrentlyinCreationException (nome beanname); } // Verifique se a definição do feijão existe nesta fábrica. BeanFactory ParentBeanFactory = getParentBeanFactory (); if (parentBeanFactory! = null &&! String nametolookup = originalBeanName (nome); if (args! = null) {// delegação ao pai com args explícitos. return (t) parentbeanfactory.getbean (nametolookup, args); } else {// sem args -> delegado ao método getBean padrão. return parentbeanfactory.getbean (nametolookup, requerirtype); }} if (! TypeCheckonly) {MarkBeanAsCreated (Beanname); } tente {final RootBeandEfinition mbd = getMergedLocalBeandEfinition (beanname); checkMergedBeandEfinition (MBD, Beanname, Args); // garante a inicialização de feijões dos quais o feijão atual depende. String [] dependson = mbd.getDependson (); if (dependentsson! = null) {for (string dependeSsonBean: dependeSson) {if (isDependent (beanname, dependsonbean)) {tiro o novo beanscreationException (mbd.getResourceDescription (), beanname, "circular depende '' ' + bEanName +" e "" "" +; } registerDependerBean (dependentSonBean, beanname); getBean (dependentSonBean); }} // Crie instância do feijão. if (mbd.issingleton ()) {// preocupação 2 sharedInstance = getsingleton (beanname, new objectFactory <ject> () {@Override public Object getObject () lança beansception {try {return catebean (beanname, mbd, args); rusexcen (tryxex {return catebean (bEanname, mbd, args); Coloque o processo de criação, para permitir a resolução circular de referência. Bean = getObjectForBeanInstance (SharedInstance, Name, Beanname, MBD); } else if (mbd.isprototype ()) {// é um protótipo -> crie uma nova instância. Objeto prototypeInstance = null; tente {antes doProTyPeCreation (beanname); prototypeInstance = createbean (beanname, mbd, args); } finalmente {AfterPrototyPeCreation (Beanname); } bean = getObjectForBeanInstance (PrototypeInstance, Name, Beanname, MBD); } else {string scopeName = mbd.getScope (); Escopo final do escopo = this.scopes.get (ScopeName); if (scope == null) {lança new ilegalStateException ("nenhum escopo registrado para o nome do escopo '" + scopename + "'"); } try {objeto scopedInstance = scope.get (beanname, new objectFactory <ject> () {@Override public Object getObject () lança beansexception {antes prototyPeCreation (beanname); try {return createBean (beanname, mbd (argsn); finalmente; Bean = getObjectForBeanInstance (ScopedInstance, Name, Beanname, MBD); } Catch (ilegalStateException ex) {THRET NOVA BEANCREATIONEXCECTIMENTO (NAME DO BEANS, "SCOPE '" + SCOPENAME + "' não é ativo para o thread atual; considere" + "definindo um proxy com escopo para este feijão se você pretende se referir a ele de um singleton", ex); }}} catch (beansexception ex) {cleanupAfterBeanCeationFailure (beanname); jogar ex; }} // Verifique se o tipo necessário corresponde ao tipo de instância real do feijão. if (requerirtype! = null && bean! = null &&! requerirtype.isassignablefrom (bean.getclass ())) {try {return getTypeconverter (). convertifNeCessary (bean, requeryType); } catch (typeMismatchException ex) {if (logger.isdebugenabled ()) {Logger.debug ("Falha ao converter o bean '" + name + "' para o tipo necessário [" + classutils.getqualifiedName (requeryType) + "], ex); } lança o novo beannotofrequiredTypeexception (nome, requerirtype, bean.getclass ()); }} retornar (t) Bean; } Esse método é muito longo, vamos falar sobre isso pouco a pouco. Vejamos o nosso foco primeiro. Object sharedInstance = getSingleton(beanName ) obtém um objeto Singleton da coleção de singletons com base no nome. Vejamos esse método, e finalmente é org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
Objeto protegido Getingleton (String Beanname, Boolean allowerlyReference) {objeto singletonObject = this.singletonObjects.get (beanname); if (singletonObject == null && iSsingleToCurrentlyinCreation (beanname)) {sincronizado (this.singletonObjects) {singletonObject = this.earlysingletonObjects.get (beanname); if (singletonObject == null && allowarlyReference) {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); } Todos devem prestar atenção a esse método, é muito importante. Mencionamos o cache de nível 3 no início, e um dos pontos de uso está aqui. Qual cache de nível 3 é? singletonObjects do cache de primeiro nível são colocados com objetos instanturados de singletonOnObjects. O segundo nível da earlySingletonObjects Store Singleton Objetos que são expostos com antecedência (não totalmente montados). Os singletonfacories de terceiro nível armazenam a fábrica de objetos do objeto a ser instanciada. Depois de explicar o cache de nível 3, vamos dar uma olhada na lógica. A primeira vez que eu venho this.singletonObjects.get(beanName) Retorna NULL. Em seguida, isSingletonCurrentlyInCreation determina se os dados podem ser obtidos no cache secundário.
public boolean IssingleToCurrentlyinCreation (string beanname) {return this.singLetonscurrentlyinCreation.contains (beanname); } O nome do feijão será incluído no conjunto singletonsCurrentlyInCreation , contém o nome de gaiola de entrada? Não há lugar para defini -lo antes, para que definitivamente não o inclua. Portanto, esse método retorna falsa e o processo subsequente não será deixado. O método getSingleton retorna nulo.
Vejamos o foco 2. Também é um getSingleton , mas é o verdadeiro processo de criação de um feijão. Podemos ver que um objeto anônimo é transmitido. O método GetObject chamado CreateBean, o método real de criar um feijão. Claro que podemos deixá -lo de lado e continuar olhando para o nosso método getSingleton
Public Object Getingleton (String beanname, ObjectFactory <?> SingletonFactory) {Assert.NotNull (Beanname, "'Beanname' não deve ser nulo"); sincronizado (this.singletonObjects) {objeto singletonObject = this.singletonObjects.get (beanname); if (singletonObject == NULL) {if (this.singLetonscurrentlyIndrestruction) {lança uma nova beancherationNotallowedException (nome do beanname, "Criação do feijão singleton não permitido enquanto o singlenses desta fábrica está em destruição" + "(não solicite um bean de um beanfactory em um método implementado!)" } if (logger.isdebugenabled ()) {Logger.debug ("Criando instância compartilhada de singleton bean '" + beanname + "'"); } beforesingLeleCreation (beanname); Newsingleton booleano = false; Records booleanosUPLEPRESEDEXCECTIONS = (this.suppressEdExceptions == NULL); if (registrosuPpressEdExceptions) {this.suppressEdExceptions = new LinkedHashSet <Cextion> (); } tente {singletonObject = singletonfactory.getObject (); Newsingleton = true; } catch (ilegalstateException ex) {// tem o objeto Singleton apareceu implicitamente nesse meio tempo -> // Se sim, prossiga com ele, pois a exceção indica esse estado. singletonObject = this.singletonObjects.get (beanname); if (singletonObject == null) {tiro ex; }} Catch (beaRCreationException ex) {if (registrosUprimedExceptions) {for (exceção suprimedException: this.suppressEdExceptions) {ex.addrelatedCause (suprimeDexception); }} jogue ex; } finalmente {if (RegistrosuPpressEdExceptions) {this.suppressEdExceptions = null; } pós -contratação (nome de beann); } if (Newsingleton) {addSingleton (beanname, singletonObject); }} return (singletonObject! = null_object? singletonObject: null); }} A primeira frase deste método Object singletonObject = this.singletonObjects.get(beanName) busca dados do cache de primeiro nível, que é definitivamente nulo. O método beforeSingletonCreation é então chamado.
Void protegido BeFeSingLeToCreation (string beanname) {if (! this.increationChecKexclusions.contains (beanname) &&! this.singLetonscurrentlyinCreation.add (beanname)) {lança uma nova beancherRencherEncreationException (BeanName); }} Entre eles está o processo de adicionar o nome do Beanname ao conjunto de concriação singletonsCurrentlyInCreation . Este conjunto é muito importante e será usado posteriormente. Em seguida, chame o método GetObject de SingletonFactory para executar o processo de criação real. Vamos dar uma olhada no verdadeiro processo de criação mencionado acima createBean A lógica principal dentro é doCreateBean .
Objeto protegido doceateBean (string final Beanname, Final RootBeandEfinition MBD, objeto final [] args) {// instanciam o feijão. Beanwrapper InstanceWrapper = null; if (mbd.issingleton ()) {instanceWrapper = this.FactoryBeanInstancecache.remove (beanname); } if (instanceWrapper == NULL) {InstanceWrapper = CreateBeanInstance (Beanname, MBD, Args); } Final Object Bean = (InstanceWrapper! = NULL? InstanceWrapper.GetWrapInstance (): NULL); Classe <?> Beantype = (instanceWrapper! = Null? Instância de vastawrapper.getwredclass (): null); // permite que os pós-processadores modificem a definição de feijão mesclado. sincronizado (mbd.postProcessingLock) {if (! mbd.postproceded) {AplicaçãoMergedBeanDefinitionPostProcessors (MBD, Beantype, Beanname); mbd.postproceded = true; }} // cache ansiosamente singletons para poder resolver referências circulares // mesmo quando desencadeadas por interfaces do ciclo de vida como o BeanFactoryAware. // preocupação3 boolean EarlySingLetonexPosure = (mbd.issingleton () && this.allowCircularReferências && iSsingLetoCurrentlyinCreation (Beanname)); if (EarlySingLetonexPosure) {if (logger.isdebugenabled ()) {Logger.debug ("Bean com cache ansiosamente '" + beanname + "' para permitir a resolução de possíveis referências circulares"); } addSingletonFactory (beanname, new ObjectFactory <ject> () {@Override public Object getObject () lança beansexception {return getearlybeanReference (beanname, mbd, bean);}}); } // Inicialize a instância do feijão. Objeto exposedObject = bean; tente {PopulateBean (Beanname, MBD, InstanceWrapper); if (exposedObject! = null) {exposedObject = InitializeBean (beanname, exposedObject, mbd); }} Catch (ex -jogável ex) {if (ex instância do beaRCreationException && beanname.equals (((beancreationException) ex) .getBeanName ()) {throw (beaRCreationException) ex; } else {tiro o novo beaRCreationException (mbd.getResourceDescription (), beanname, "inicialização do feijão falhou", ex); }} if (comounSingLetonexposure) {Object EarnSingLetonReference = Getingleton (Beanname, false); if (EarnSingletonReference! = null) {if (exposedObject == bean) {exposedObject = EarnSingletonReference; } else if (! this.allowRawinjectionDespiteWrapping && hasDependentBean (beanname)) {String [] dependentBeans = getDependentBeans (beanname); Set <string> realdependentBeans = new LinkedHashSet <String> (dependentBeanS.Length); para (String dependentBean: dependentBeans) {if (! RemoveSingLetonifcreatedfortyPeCheckonly (dependentBean)) {realdependentBeanS.add (dependentBean); }} if (! realdependentBeans.isempty ()) {tire o novo beanscurrentlyinCreationException (nome do feijão, "Bean with Name '" + Beanname + "' foi injetado em outros beans [" + stringutils.collectionTocommadelImitedstring (realDependerBeanes) + "] na versão em que a parte de base mais ou menos), na parte de referência. Isso disse que outros feijões não usam a versão final do feijão " +". }}}}} // Registre Bean como descartável. tente {registerDisposableBeanifneCessary (Beanname, Bean, MBD); } catch (beandEfinitionValidationException ex) {tiro o novo beaRCreationException (mbd.getResourceDescription (), beanname, "assinatura de destruição inválida", ex); } retornar exposedObject; } createBeanInstance cria um objeto usando reflexão. Vamos dar uma olhada no ponto de julgamento 3, valor do atributo earlySingletonExposure . Um dos pontos de julgamento isSingletonCurrentlyInCreation(beanName)
public boolean IssingleToCurrentlyinCreation (string beanname) {return this.singLetonscurrentlyinCreation.contains (beanname); } Descobri que o conjunto de incriação de singletonscorrerly é usado. O nome do feijão foi preenchido nas etapas acima, para que possa ser encontrado. Portanto, a propriedade earlySingletonExposure é determinada como verdadeira em combinação com outras condições, e o processo a seguir é adicionado addSingletonFactory . Aqui está uma fábrica de objetos correspondente ao nome do feijão (a). A implementação de seu método getObject é alcançada através getEarlyBeanReference . Primeiro, vamos dar uma olhada na implementação de addsingletonfactory
Void protegido AddsingletonFactory (String Beanname, ObjectFactory <?> SingletonFactory) {Assert.NotNull (SingletonFactory, "Singleton Factory não deve ser nulo"); sincronizado (this.singletonObjects) {if (! this.singletonObjects.containsKey (beanname)) {this.singletonfactory.put (beanname, singletonfactory); this.earlysingletonObjects.remove (beanname); this.RegisterDSingLetons.add (Beanname); }}} Armazenamento de dados nos singletonfacories do terceiro nível de cache, limpando os dados do cache do segundo nível com base no nome do beann. Há um ponto muito importante aqui, que é definir o valor no cache de terceiro nível, que é o ponto principal do processamento de dependências circulares de Spring. O método getEarlyBeanReference é uma implementação do GetObject. Pode -se simplesmente considerar que ele retorna uma instância de objeto que é preenchida com A. Depois de definir o cache de nível 3, o processo de preenchimento das propriedades do objeto A começa. A descrição a seguir não possui avisos de código -fonte, apenas uma breve introdução.
Ao preencher A, descobri que é necessário um feijão do tipo B, então continuei chamando o método getBean para criá -lo. O processo de memória é exatamente o mesmo que acima. Depois fui ao processo de preencher um feijão do tipo C, e a mesma chamada getbean (c) é chamada para executar. Ao preencher uma propriedade A, liguei para getbean (a). Vamos continuar daqui que chamei Object sharedInstance = getSingleton(beanName), o mesmo código, mas a lógica de processamento é completamente diferente.
Objeto protegido Getingleton (String Beanname, Boolean allowerlyReference) {objeto singletonObject = this.singletonObjects.get (beanname); if (singletonObject == null && iSsingleToCurrentlyinCreation (beanname)) {sincronizado (this.singletonObjects) {singletonObject = this.earlysingletonObjects.get (beanname); if (singletonObject == null && allowarlyReference) {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); } Ainda assim, o objeto é obtido a partir de singletonobjects não pode ser obtido. Como A está no conjunto de singletonsCurrentlyInCreation , ele entra na lógica a seguir e a leva a partir do cache de cache earlySingletonObjects , mas ainda não foi encontrado. Em seguida, ele encontra a fábrica de objetos correspondente a partir dos singletonFactories Ligue para getObject para obter o objeto de instância de A que não foi completamente preenchido e exclui os dados de cache de terceiro nível, preenche os dados de cache de segundo nível e retorna esse objeto A. C depende do preenchimento de instância de A, embora este A esteja incompleto. Não importa como o enchimento do estilo C seja concluído, você pode colocar C nos singletonObjects de primeiro nível de cache e limpar os dados dos caches de segundo e terceiro nível ao mesmo tempo. No mesmo processo, se C depende de B é preenchido, B será preenchido. Da mesma forma, se B depende de A é preenchido, a é preenchido. É assim que a primavera resolve referências circulares.
O exposto acima é todo o conteúdo deste artigo. Espero que seja útil para o aprendizado de todos e espero que todos apoiem mais o wulin.com.