Este artigo apresenta uma breve discussão sobre o princípio da injeção de dependência dos contêineres do IOC da primavera e o compartilha com você, como segue:
A principal tarefa de inicializar o contêiner do COI é estabelecer um mapa de dados de definição do BeaNDefinition no contêiner do IOC. Não vi o contêiner do COI injetando o relacionamento de dependência do feijão.
Supondo que o contêiner atual do IOC tenha carregado informações de feijão definidas pelo usuário, a injeção de dependência ocorre principalmente em dois estágios.
Em circunstâncias normais, é acionado quando o usuário pede um feijão do contêiner do COI pela primeira vez.
No entanto, podemos controlar o atributo de initência preguiçoso nas informações de BandEfinition para permitir que o contêiner pré-insegure o feijão, ou seja, o processo de injeção de dependência de certos grãos é concluído durante o processo de inicialização.
1. Injeção de dependência desencadeada por getbean
Na interface básica de contêiner do IOC BeanFactory, há uma definição de interface para getBean. A implementação dessa interface é onde a injeção de dependência do gatilho ocorre. Para entender melhor o processo de injeção de dependência, começamos com a classe Base AbstractBeanFactory do DefaultListableBeanFactory para dar uma olhada na implementação do getBean
// Aqui está a implementação da interface BeanFactory, como o método getBean Interface // Esses métodos de interface getBean são implementados chamando o DogetBean @Override Public Object getBean (nome da string) lança beansexception {return DogetBean (nome, null, null, false); } @Override public <T> t getBean (nome da string, classe <T> requerirtype) lança beansexception {return DogetBean (nome, requerirtype, nulo, false); } @Override Public Object getBean (nome da string, objeto ... args) lança beansexception {return DogetBean (nome, nulo, args, false); } public <T> t getBean (nome da string, classe <t> requerirtype, objeto ... args) lança beansexception {return DogetBean (nome, requerirtype, args, false); } // É aqui que o feijão é realmente obtido, ou seja, onde a injeção de dependência é acionada @suppresswarnings ("desmarcada") protegida <T> t DogetBean (Nome final da string, classe final <T> requerirtype, objeto final [] args, boolean typeCheckonly) throwsexexception {string string [] args, Boolean) Objeto Bean; // Verifica ansiosamente o singleton cache quanto a singletons registrados manualmente. // Verifica ansiosamente o singleton cache quanto a singletons registrados manualmente. // Verifica ansiosamente o singleton cache para obter o registro manual Singletons // busca os feijões do cache primeiro e processa os feijões singleton que foram criados. Não crie repetidamente o objeto compartilhado; if (sharedInstance! = null && args == null) {if (logger.isdebugenabled ()) {if (issingletoncurrentyinCreation (beanname)) {Logger.debug ("Retornando earamente cache de singleton bean '" + bEanname + "early que é totalmente confundido com a instância do singleton" + bEanname + ", que não é o singleton" + bEanname + ", que é um pouco de singleton; } else {Logger.debug ("Retornando a instância em cache de singleton bean '" + beanname + "'"); }} // O GetObjectForBeanInstance aqui completa o processamento relevante do FactoryBean para obter o processamento relevante do FactoryBean para obter os resultados da produção do FactoryBean. A diferença entre Beanfactory e FactoryBean foi mencionada anteriormente. Este processo será analisado em detalhes posteriormente. = 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 BEANDefinition no contêiner do IOC existe. Se não existir na fábrica atual, siga a cadeia de beanfactory pai e procure para cima o 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 {// obtém beandEfinition final rootbeandEfinition mbd = getMergedLocalBeanDefinition (beanname); checkMergedBeandEfinition (MBD, Beanname, Args); // garante a inicialização de feijões dos quais o feijão atual depende. // obtém recursivamente todos os grãos dos quais o feijão atual depende (se houver) string [] dependson = mbd.getDependson (); if (dependentSon! = null) {for (string dep: dependeSson) {if (isDependent (beanname, dep)) {tiro o novo beancreationException (mbd.getResourceDescription (), beanname, "nome da circular depende entre '" + beanname + "' e '" " +" ""); } registerDependerBean (dep, beanname); getBean (dep); }} // Crie a instância do feijão singleton chamando o método CreateBean se (mbd.issingleton ()) {sharedInstance = getsingleton (beanname, new objectFactory <jectFaction> () {@Override public Objecjet GetObject () lança beansception {try {returtBean (bdeanname (bdeanname) Remova explicitamente a instância do cache de singleton: pode ter sido colocado lá // ansiosamente pelo processo de criação, para permitir a resolução de referência circular. Bean = getObjectForBeanInstance (SharedInstance, Name, Beanname, MBD); } // Este é o local para criar um protótipo Bean se (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. // A verificação do tipo é realizada no feijão criado aqui. Se não houver problema, o feijão recém -criado será devolvido. Este feijão já é um feijão que contém a dependência se (requerirType! = Null && bean! = Null &&! Requerirtype.isassignablefrom (bean.getclass ())) {try {return getTypeconverter (). } catch (typeMismatchException ex) {if (logger.isdebugenabled ()) {logger.debug ("falhou ao converter bean '" + name + "' para o tipo necessário '" + classutils.getqualifiedName (requeryType) + "", ex); } lança o novo beannotofrequiredTypeexception (nome, requerirtype, bean.getclass ()); }} retornar (t) Bean; }A injeção de dependência é acionada aqui. A injeção de dependência ocorre quando os dados do BeandEfinition no contêiner foram estabelecidos. Embora possamos descrever o contêiner do COI da maneira mais simples, ou seja, tratá -lo como um hashmap, só podemos dizer que este hashmap é a estrutura de dados mais básica do contêiner, não o contêiner inteiro do COI.
Esse processo de injeção de dependência será explicado em detalhes abaixo. A Figura 1.1 mostra o processo geral de injeção de dependência.
Figura 1.1 Processo de injeção de dependência
GetBean é o ponto de partida da injeção de dependência. Depois disso, o CreateBean em abstrateaUTowirecapableBeanFactory será chamado para produzir o feijão necessário, e a inicialização do feijão também é processada, como a implementação da definição de atributo init-method em BeandEfinition, o pós-processador de feijão, etc. A seguir, é para entender esse processo através do código CreateBean
@Override Protected Object CreateBean (String beanname, rootBeandEfinition mbd, objeto [] args) lança beanscreationException {if (logger.isdebugenabled ()) {logger.debug ("criando instância de bean '" + beanname + "'"); } RootBeAndEfinition mbdTouse = mbd; // Verifique se a classe Bean está realmente resolvida neste momento e // clone a definição do feijão em caso de uma classe // resolvida dinamicamente que não pode ser armazenada na definição de feijão mesclado compartilhado. // Aqui determinamos se o feijão a ser criado pode ser instanciado, se essa classe pode ser carregada através da classe de carregador de classe <?> ResolvedClass = ResolveBeanclass (MBD, Beanname); if (resolvidoclass! = null &&! mbd.hasbeanClass () && mbd.getbeanClassName ()! = null) {mbdTouse = new RootBeandEfinition (MBD); mbdTouse.setBeanclass (resolvidoclass); } // Preparar substituir o método. tente {mbdTouse.PreparemetHoDoverrides (); } catch (beandEfinitionValidationException ex) {tiro o novo BeandEfinitionStoreException (mbdtouse.getResourceDescription (), beanname, "Validação de substituições de método falhou", ex); } tente {// Dê a BeanPostProcessors a chance de retornar um proxy em vez da instância do feijão de destino. // Se o feijão configurou o pós -processador, o objeto de proxy retornado Bean = ResolveBeforeInstantiation (Beanname, mbdToous); if (bean! = null) {return bean; }} catch (throwable ex) {tire nova beancreationException (mbdtoous.getResourceDescription (), beanname, "BeanPostProcessor antes da instanciação do feijão falhou", ex); } tente {objeto beanInstance = DocReateBean (Beanname, mbdTouse, args); if (logger.isdebugenabled ()) {Logger.debug ("Terminou de criar a instância do bean '" + beanname + "'"); } retornar BeanInstance; } catch (beancreationException ex) {// Uma exceção detectada anteriormente com o contexto de criação de feijão adequado já ... jogue ex; } catch (implicitamenteppearedSingLetonexception ex) {// Uma ilegalStateException a ser comunicada para deixar o padrão de seleção } catch (ex throwable ex) {tiro o novo beancreationException (mbdtouse.getResourceDescription (), nome de beanname, "exceção inesperada durante a criação do feijão", ex); }} // ao lado do docriate para ver como os feijões são gerados por objeto protegido DocreateBean (string final, nome do rootBeandEfinition mbd, objeto final [] args) {// instanciam o feijão. // usado para manter o objeto de feijão criado Beanwrapper InstanceWrapper = null; // Se for um singleton, primeiro limpe o feijão com o mesmo nome no cache if (mbd.issingleton ()) {instanceWrapper = this.FactoryBeanInstanceCache.remove (beanname); } // Este é o local para criar o feijão e é feito pelo CreateBeanInstance if (instanceWrapper == null) {// Crie uma nova instância com base no feijão especificado usando a estratégia correspondente, como: método de fábrica, construtor injeção automática, argts simples. } 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. // é necessário expor com antecedência: Singleton e permitir dependências cíclicas e o feijão atual está sendo criado, detecte dependências cíclicas booleanas EarlySingLetonexPosure = (mbd.issingleton () && this.allowcircularreferences && iSingLencurrentrelyIrcreation (Beanname)); if (EarlySingLetonexposure) {if (Logger.isdebugenabled ()) {Logger.debug ("Cache ansiosamente em cache de bean '" + beanname + "' para permitir a resolução de possíveis referências circulares"); } // Para evitar dependências do ciclo tardio, o ObjectFactory que cria uma instância pode ser adicionado à fábrica antes que a inicialização do feijão seja concluída. AddSingLeToNFactory (Beanname, new ObjecjetFactory <ject> () {@Override public Object getObject () lança beansexception {// depende de referências a feijões novamente, principalmente usando o SmartInstantialyAciationAchee, o que não deve ser o que devolve o que devolve a BEANS para o bean postProcess; getarlybeanReference (Beanname, MBD, Bean); } // Inicialize a instância do feijão. // Esta é a inicialização do feijão, e a injeção de dependência geralmente ocorre aqui. Esse ExposeDObject se arrepende de retornar como o feijão após o processamento da inicialização. Objeto exposedObject = bean; tente {// coloque o feijão e injete cada valor de atributo. Entre eles, pode haver atributos que dependem de outros feijões, o feijão de dependência será inicializado recursivamente preenchido (Beanname, MBD, InstanceWrapper); if (exposedObject! = null) {// chamando o método de inicialização, como init-method 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); // EarlySingLetonReference não está vazio apenas se uma dependência circular for detectada se (comounSingletonReference! = null) {if (exposeDObject == bean) {// Se exposedObject não for alterado no método de inicialização, ele não é aprimorado exposedObject = EarlySingleTonefereference; } else if (! this.allowRawinjectionDespiteWrapping && hasDependentBean (beanname)) {String [] dependentBeans = getDependentBeans (beanname); Set <string> realdependentBeans = new LinkedHashSet <String> (dependentBeanS.Length); para (String dependentBean: dependentBeans) {// Dependência de detecção if (! RemovesingletonifcreatedfortyPecheckonly (dependentBean)) {realdependentBeans.add (dependentBean); }} // Porque o feijão depende depois que o feijão é criado deve ter sido criado, o dependente real não está vazio, o que significa que o feijão depende depois que o feijão atual é criado, não foi criado, que é o nome (bate -breathen de dependência (! foi injetado em outros feijões [" + stringutils.collectionToMadeLimitedString (RealDependentBeans) +"] em sua versão bruta como parte de uma referência circular, mas acabou sendo ", que se refere a que o tipo de fita", que não é o que é o que não faz com que o tipo de bean ", que não é possível usar o tipo de queda, que não é possível usar o tipo de queda, que não é possível usar o tipo de queda. 'permitir a bandeira' desligado, por exemplo. "); }}}}} // Registre Bean como descartável. tente {// registrar bean com base no escopo RegisterDisposableBeanifneCessary (Beanname, Bean, MBD); } catch (beandEfinitionValidationException ex) {tiro o novo beaRCreationException (mbd.getResourceDescription (), beanname, "assinatura de destruição inválida", ex); } retornar exposedObject; }A injeção de dependência envolve realmente dois processos principais
Do exposto, podemos ver que os métodos que estão particularmente intimamente relacionados à injeção de dependência incluem
CreateBeanInstance
Gerar objetos java contidos em feijão
PoPulateBean.
Processando o processo de processamento das propriedades de vários objetos de feijão (ou seja, o processo de processamento de dependência)
Vamos dar uma olhada no código -fonte CreateBeanInstance primeiro
/** * Crie uma nova instância para o feijão especificado, usando uma estratégia de instância apropriada: * Método de fábrica, construção automática de construtor ou instância simples. * @param beanname O nome do feijão * @param mbd A definição de feijão para o feijão * @param Argum argumentos explícitos para usar para o método construtor ou de fábrica Invocação * @return Um beanwrapper para a nova instância. apontar. // confirma que a classe da instância do feijão que você deseja criar pode ser instanciada de classe <?> Beansclass = resolvebeanclass (mbd, beanname); if (beansclass! = null &&! modifier.ispublic (beansclass.getModifiers ()) &&! mbd.isnonpublicaccessllowed ()) {lança nova beancreationException (mbd.getResourcedescription (), benname, "bean benging não é público e público não } Fornecedor <?> InstânciaspPlier = mbd.getInstancesPlier (); if (Instâncias Supplier! = null) {return obtendFromFromSupplier (Instâncias Supplier, Beanname); } // Se o método da fábrica não estiver vazio, use a estratégia do método de fábrica para instanciar o feijão if (mbd.getFactoryMethodName ()! = Null) {return instantiateUsingFactoryMethod (beanname, mbd, args); } // atalho ao recriar o mesmo feijão ... boolean resolvido = false; boolean AutowireNeCesary = false; se (args == null) {sincronizado (mbd.constructorargumentlock) {// Uma classe possui vários construtores, cada construtor possui parâmetros diferentes; portanto, antes de ligar, você precisa bloquear o método de fábrica do construtor ou de acordo com os parâmetros; AutoWIReNeCesary = mbd.ConstructorRargudesResolved; }}} // Se tiver sido analisado, use o método do construtor analisado sem travar novamente se (resolvido) {if (AutoWIReNeCesary) {// construtor injeta automaticamente retorna a AutoWIReConstructor (beanname, mbd, null, null); } else {// construtor usando o construtor padrão para construir instantiateBean (nome do beanname, mbd); }} // precisa determinar o construtor ... // instanciar o feijão usando o construtor construtor <?> [] CTors = determineConstructorsFromeanPostprocessors (BeansClass, Beanname); if (cTors! = NULL || mbd.getResolvedAUTOWIREMODE () == rootbeandEfinition.autowire_constructor || mbd.hasconstructorargumentvumentValues () ||! } // Sem manuseio especial: basta usar o construtor não-arg. // instanciar o feijão usando seu construtor padrão; } /*** instanciam o feijão dado usando seu construtor padrão. * @param beanname O nome do feijão * @param mbd A definição de feijão para o feijão * @return um bando para a nova instância */// o instanciado mais comum protegido de beanwrapper instaateBean (string final beanname, o bate -tending final da string. A estratégia de instanciação padrão é // cglibsubclassingInsinAntiationStrategy, ou seja, instanciar o feijão usando o CGLIB. tente {objeto beanInstance; Pai do Beanfactory final = this; if (system.getSecurityManager ()! = null) {beanInstance = accessController.Doprivileged (novo privilegiado <jectAction <ject> () {@Override public Object run () {return getInstAntiationStrateggy (). Instantiate (mbd, beanname, pai); } else {beanInstance = getInstantiationStrategy (). Instantiate (MBD, Beanname, pai); } Beanwrapper bw = new BeanWrapperImpl (beanInstance); initbeanwrapper (BW); retornar BW; } catch (ex throwable ex) {lança nova beancreationException (mbd.getResourceDescription (), beanname, "instanciação do feijão falhou", ex); }}O CGLIB é usado aqui para instanciar feijões. O CGLIB é uma biblioteca de classes para geradores de bytecode, que fornece uma série de APIs para fornecer a função de gerar e converter o Java Bytecode.
Na primavera AOP, o CGLIB também é usado para aprimorar o Java Bytecode. Nos contêineres do IOC, para entender como usar o CGLIB para gerar objetos de feijão, você precisa olhar para a classe SimpleInstiationStrategy. É a classe padrão usada pela mola para gerar objetos de feijão. Ele fornece dois métodos para instanciar objetos de feijão.
classe pública SimpleInstantiationStrategy implementa instantationstrategy {@Override public Object Instantiate (rootbeandEfinition bd, string beanname, proprietário de beanfactory) {// não substitui a classe com cglib se não houver substituição. if (bd.getMethodOverrides (). isEmpty ()) {// Aqui você obtém o construtor ou método de fábrica especificado para instanciar o beanconstrutor <?> construtortorouse; sincronizado (bd.constructorRGumentLock) {constructorouse = (construtor <?>) bd.resolvedConstructororFactoryMethod. if (constructorouse == null) {classe final <?> clazz = bd.getbeanclass (); if (clazz.isinterface ()) {lança nova beanInstantiationException (clazz, "a classe especificada é uma interface"); } tente {if (system.getSecurityManager ()! = null) {constructorouse = accessController.Doprivileged (new privilegedExceptionActionAction <construtor <? >> () {@override public construtor (Class) [); } else {construtortouse = clazz.getDecLaredConstructor ((classe []) null); } bd.ResolvedConstrucTororFactoryMethod = ConstructorTouse; } catch (throwable ex) {tiro o novo beanInstantiationException (clazz, "nenhum construtor padrão encontrado", ex); }}} // instanciado através de beanutils. A instanciação desse beanutils instancia o feijão através do construtor. Nos Beanutils, você pode ver a chamada específica. } else {// instanciam o objeto retornar instantiateWithMethodinjection (bd, beanname, proprietário); }}}Manuseio de dependências entre feijões
A entrada no processamento de dependência é o método PopulateBean mencionado acima. Como existem muitos aspectos envolvidos, não vou postar o código aqui. Uma breve introdução ao processo de processamento de dependência: no método PopulateBean,
Primeiro, obtenha o valor da propriedade definido na BeandEfinition e, em seguida, inicie o processo de injeção de dependência.
Primeiro, a injeção do AutoWire pode ser processada, ByName ou ByType, e os atributos são injetados.
Então você precisa analisar a referência de feijão. Após a análise da lista de analistas, o ManageSet, o gerente, etc., você preparou condições para injeção de dependência. É aqui que você realmente define o objeto de feijão para outra propriedade de feijão depende, e as propriedades processadas são várias.
A injeção de dependência ocorre nos Valores do SetProperty do Beanwrapper, mas a conclusão específica é implementada na subclasse BeanwrapatripperImpl. Ele concluirá a injeção do valor da propriedade do feijão, incluindo a injeção de matriz, a injeção de classes de coleta, como a LIST e a injeção de classes que não sejam colecionantes.
Após uma série de injeções, o processo de injeção de dependência de várias propriedades do feijão é concluído.
Durante o processo de criação de feijões e injeção de dependência de objetos, a injeção de dependência precisa ser concluída recursivamente com base nas informações na concepção de BeaNDefinition.
A partir dos processos de recursão anteriores, podemos ver que essas recursões são todas portáteis com o getBean.
Uma recursão é encontrar o feijão necessário e criar a chamada recursiva para o feijão no sistema de contexto;
Outra recursão é chamar o método getBean do contêiner recursivamente durante a injeção de dependência para obter o feijão de dependência do feijão atual e também acionar a criação e a injeção do feijão de dependência.
Ao realizar a injeção de dependência nas propriedades de um feijão, o processo de análise também é um processo recursivo. Dessa forma, de acordo com a dependência, a criação e a injeção do feijão são concluídas camadas por camada até que a criação do feijão atual seja finalmente concluída. Com a criação deste feijão de nível superior e a conclusão de sua injeção de dependência de atributos, significa que a solução de injeção de toda a cadeia de dependência relacionada ao feijão atual é concluída.
Após a conclusão da criação de feijão e injeção de dependência, uma série de feijões vinculados por dependências são estabelecidos no contêiner do COI. Este feijão não é mais um objeto Java simples. Após o estabelecimento da relação de dependência entre a série Bean e o feijão, ela pode ser usada de maneira muito conveniente para aplicações de nível superior através dos métodos de interface relevantes do COI.
2. Atributo preguiçoso e pré-instância
No método de atualização anterior, podemos ver que o FinishBeanFactoryInitialization é chamado para processar os feijões configurados com a entrada preguiçosa.
De fato, nesse método, o processamento do atributo de initência preguiçoso é encapsulado e o processamento real é feito no método pré-instantiático de Lei do contêiner básico do DefaultListableBeanFactory. Este método conclui os feijões singleton pré-instalados, e essa conclusão pré-instalada é delegada inteligentemente ao contêiner a ser implementado. Se for necessário o pré-instalação, o getBean será usado aqui para desencadear a injeção de dependência. Comparado com os gatilhos normais de injeção de dependência, o tempo e a ocasião de acionamento são apenas diferentes. Aqui, a injeção de dependência ocorre durante o processo de atualização do contêiner, ou seja, durante o processo de inicialização do contêiner do COI, diferentemente da injeção de dependência comum, quando o contêiner solicita o feijão pela primeira vez após o recipiente do COI é inicializado através do getBean.
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.