Protótipo do COI da primavera
O núcleo básico e o ponto de partida da estrutura da mola são, sem dúvida, o COI. Como a tecnologia principal fornecida pelos contêineres de mola, o COI concluiu com êxito a inversão de dependências: do gerenciamento ativo da classe principal de dependências ao controle global das dependências pelos contêineres da mola.
Quais são os benefícios de fazer isso?
Obviamente, é o chamado "dissociação", que pode tornar a relação entre os módulos do programa mais independente. A primavera precisa controlar apenas as dependências entre esses módulos e criar, gerenciar e manter esses módulos com base nessas dependências durante o processo de inicialização e inicialização do contêiner. Se você precisar alterar as dependências entre os módulos, nem precisará alterar o código do programa. Você só precisa modificar as dependências alteradas. A primavera restabelecerá essas novas dependências no processo de iniciar e inicializar o contêiner novamente. Nesse processo, é necessário observar que o próprio código não precisa refletir a declaração da situação de dependência específica do módulo, mas só precisa definir a interface do módulo necessário. Portanto, essa é uma idéia típica orientada para interface. Ao mesmo tempo, é melhor expressar as dependências na forma de arquivos de configuração ou anotações. As classes de processamento de mola relevantes montarão módulos com base nesses arquivos de configuração externos ou digitalizarão a anotação para chamar o processador de anotação interna para montar módulos para concluir o processo do COI.
O objetivo do COI é uma injeção de dependência chamada DI. Através da tecnologia do COI, o Ultimate Container nos ajudará a concluir a injeção de dependência entre os módulos.
Além disso, o ponto final é que, no processo do COI da primavera, devemos sempre estar claros sobre a linha principal acima. Não importa quão complexos sejam a sintaxe e a estrutura de classe em tempo real, sua função e propósito são iguais: é concluir a "montagem" do módulo, dependendo do arquivo de configuração descrito como o conjunto "desenho". A sintaxe complexa é apenas um meio de alcançar esse objetivo.
O chamado protótipo do COI, para mostrar o diagrama esquemático mais simples do COI, podemos fazer um protótipo completamente simples para ilustrar esse processo:
Primeiro, existem vários módulos que definimos, incluindo o módulo principal e o módulo de dependência definido pelas duas interfaces:
classe MainModule {private DependModulea Modulea; private DependModuleB ModuleB; public DependModulea getModulea () {return modulea; } public void setModulea (dependModulea modulea) {this.modulea = modulea; } public DependModuleB getModuleB () {return ModuleB; } public void setModuleB (dependeDModuleB ModuleB) {this.moduleb = moduleb; }} interface DependModulea {public void funcodrmodulea ();} interface DependModuleB {public void funcodrmoduleBB ();} classe DependeDModuleAImpl implementa dependedModulea {@Override public void funcommommommommodEa () {System.out.println ("Override FuncommommodommodomAmodEa () {System.out.printlnnnnnnnnnnnnnnnnnnn (" This IsnUled FuncommommommommommodEa () {System.out.printlnnnnnnnnnnn ("Thishingride funcommommommommommommommommommodEa () {System.out.println (" }} classe DependeDModuleBimpl implementa dependeDModuleB {@Override public void funcrmoduleB () {System.out.println ("Este é o functão do módulo B"); }}Se não adotarmos o COI, mas dependemos do próprio módulo principal para controlar a criação de seu módulo dependente, será assim:
classe pública simplesiocdemo {public static void main (string [] args) lança classNotFoundException {mainmodule mainModule = new mainModule (); mainmodule.setModulea (new DependModuleAimpl ()); mainmodule.setModuleB (new DependModuleBimpl ()); mainModule.getModulea (). funcfrodulea (); mainmodule.getModuleB (). FuncFrodleMeB (); }}Esta é a nossa definição simplificada de protótipo de contêiner do IOC. Quando o contêiner é inicializado após a inicialização, ele lerá o arquivo de configuração gravado pelo usuário. Aqui, pegamos o arquivo de configuração de propriedades simples como exemplo. Somente quando o usuário chama o método getBean, o feijão correspondente será realmente montado e carregado de acordo com o arquivo de configuração. Um mapa usado para salvar o feijão montado é mantido dentro do protótipo de contêiner que definimos. Se houver um feijão que atenda aos requisitos, ele não precisará ser criado novamente:
classe SimpleIcocontainer {Propriedades privadas Propriedades = new Properties (); mapa privado <string, objeto> moduleMap = new hashmap <> (); {try {Properties.load (new FileInputStream (novo arquivo ("Simpleioc.properties"))); } catch (Exceção e) {e.printStackTrace (); }} public Object getBean (string moduleName) lança classNotFoundException {objeto instantaBJ; if (moduleMap.get (moduleName)! = null) {System.out.println ("Return Old Bean"); retornar moduleMap.get (moduleName); } System.out.println ("Criar New Bean"); String fullClassName = Properties.getProperty (moduleName); if (fullclassName == NULL) lança o novo ClassNotFoundException (); else {classe <? estende objeto> clazz = classe.ForName (FullClassName); tente {instanceObj = clazz.newInstance (); InstanceObj = BuildattachedModules (ModuleName, InstanceObJ); moduleMap.put (moduleName, instanceObj); retornar instanceObj; } catch (instantiationException e) {e.printStackTrace (); } catch (ilegalAccessException e) {E.PrintStackTrace (); }} retornar nulo; } Private Object BuildAtTachEdModules (String ModuleName, Object InstanceObj) {Set <String> PropertiesKeys = Properties.StringPropertyNames (); Campo [] campos = instanceObj.getClass (). GetDecLaredFields (); for (string key: PropertiesKeys) {if (key.contains (moduleName) &&! key.equals (moduleName)) {try {class <? estende objeto> clazz = classe.ForName (Properties.getProperty (Properties.getProperty (KEY))); para (campo de campo: campos) {if (field.gettype (). isassignablefrom (clazz)) field.set (instanceObj, clazz.newInstance ()); }} catch (Exceção e) {e.printStackTrace (); }}} retornar a InstanceObj; }}Este é o arquivo de configuração de dependência que escrevemos usando o arquivo de configuração de propriedades. Este arquivo de configuração é o "desenho" do nosso módulo de montagem. A sintaxe aqui é completamente definida por nós. No recipiente real do IOC da primavera, para expressar uma lógica de dependência mais complexa, será usado um arquivo de configuração de formato XML mais desenvolvido ou uma configuração de anotação mais recente, e o processador de anotação será usado para concluir a análise do desenho:
mainmodule = com.rocking.demo.mainmoduleMainModule.modulea = moduleamAinmodule.moduleb = moduleBmodulea = com.rocking.demo.depêndmoduleAimplModuleB = com.rocking.demo.dencendModuleBimpl
Este é o código de teste. Pode -se observar que podemos obter módulos completamente que atendem aos requisitos através do contêiner do COI que definimos. Ao mesmo tempo, também podemos descobrir que o contêiner que definimos pode manter esses feijões para nós. Quando um feijão foi montado e criado, ele não precisa ser criado novamente.
public class SimpleiocDemo {public static void main (string [] args) lança classNotFoundException {Simpleioccontainer container = new Simpleioccontainer (); DependedModulea modulea = (dependeDModulea) contêiner.getBean ("modulea"); modulea.funcfrodulea (); DependeDModuleB ModuleB = (DependeDModuleB) container.getBean ("ModuleB"); moduleb.funcfrodleMeB (); MainModule mainModule = (mainmodule) container.getBean ("mainmodule"); mainModule.getModulea (). funcfrodulea (); mainmodule.getModuleB (). FuncFrodleMeB (); container.getBean ("mainModule"); }}Este é o protótipo de contêiner do COI que criei com base na idéia básica do COI. Embora o COI da primavera tenha uma sintaxe complexa, as tarefas concluídas no final são as mesmas no centro, as chamadas "todas as mudanças não serão separadas de sua essência".
Processo específico do COI da primavera
Na última vez, foi mostrado o protótipo da implementação geral do COI. Então, como implementar especificamente o processo de carregamento de Pojos na estrutura de mola deste contêiner com base na configuração de meta de metadados? Existem muitos lugares em todo o processo de trabalho de contêiner do COI da primavera projetado para serem bastante flexíveis, fornecendo aos usuários muito espaço para concluir suas próprias tarefas, em vez de apenas concluir o processo mecânico do contêiner.
Este é o diagrama de processos de todo o processo de trabalho do contêiner do COI:
1. Fase de inicialização de contêineres (1) Carregando informações do arquivo de configuração (2) Analisando informações do arquivo de configuração (3) Assembléia BeandEfinition
(4) Pós-processamento primeiro, meta-informações, como arquivos de configuração ou anotações e informações da classe Javabean, são carregadas no contêiner do IOC. O contêiner lê um arquivo de configuração do formato XML. Este arquivo de configuração é uma dependência declarada pelo usuário e pela montagem que precisa de atenção especial. É um "desenho externo" precoce para montar o feijão. O mecanismo de análise no contêiner pode analisar a meta-informação do caractere no formulário de texto que escrevemos em uma efinição de beanse que pode ser reconhecida dentro do recipiente, que pode entender a efinição. Torna -se uma estrutura de classe semelhante ao mecanismo de reflexão. Esta beandEfinition obtida analisando os Javabeans e os arquivos de configuração obtém a estrutura básica da montagem de um Javabean que atenda aos requisitos. Se você precisar modificar a concessão do BeaNDefinition, além da concessão do BeaNDefinition, esse pós-processamento é realizado. O pós-processamento é geralmente processado através do beanFactoryPostProcessor na estrutura da primavera.
Ainda usamos os exemplos que usamos na última vez para ilustrar o princípio operacional desta definição do BeandE: existem três feijões, o principal módulo principal e os módulos de dependência dependem de dependModulea e dependModuleB. O primeiro depende dos dois últimos módulos. No arquivo de configuração, geralmente declaramos dependências como esta:
<? xml versão = "1.0" coding = "utf-8"?> <Beans xmlns = "http://www.springframework.org/schema/beans" xmlns: xsi = "http:/wwww.w3 xsi: schemalocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-bans-3.0.xsd"> <bean id = "mainmodule">> </property> <propriedade name = "Moduleb"> <ref bean = "Moduleb"/> </Property> </bean> <bean id = "Modulea"> </ Bean> <bean id = "moduleb"> </shean> </ Beans>
Este é o nosso programa demonstrando a montagem de um contêiner de beanfactory padrão (uma das implementações dos contêineres do IOC da primavera) no arquivo de configuração acima:
classe MainModule {private DependModulea Modulea; private DependModuleB ModuleB; public DependModulea getModulea () {return modulea; } public void setModulea (dependModulea modulea) {this.modulea = modulea; } public DependModuleB getModuleB () {return ModuleB; } public void setModuleB (dependeDModuleB ModuleB) {this.moduleb = moduleb; }} interface DependModulea {public void funcodrmodulea ();} interface DependModuleB {public void funcodrmoduleBB ();} classe DependeDModuleAImpl implementa dependedModulea {@Override public void funcommommommommodEa () {System.out.println ("Override FuncommommodommodomAmodEa () {System.out.printlnnnnnnnnnnnnnnnnnnn (" This IsnUled FuncommommommommommodEa () {System.out.printlnnnnnnnnnnn ("Thishingride funcommommommommommommommommommodEa () {System.out.println (" }} classe DependeDModuleBimpl implementa dependeDModuleB {@Override public void funcrmoduleB () {System.out.println ("Este é o functão do módulo B"); }} classe pública simplesiocdemo {public static void main (string [] args) lança classNotFoundException {defaultListableBeanFactory beanFactory = new DefaultListableBeanFactory (); XMLBeAndEfinitionReader Reader = new XMLBeandEfinitionReader (BeanFactory); reader.loadBeandEfinitions ("beans.xml"); MainModule mainModule = (mainModule) beanFactory.getBean ("mainModule"); mainModule.getModulea (). funcfrodulea (); mainmodule.getModuleB (). FuncFrodleMeB (); }}Aqui, nosso arquivo de configuração e Javabean são carregados e lidos e analisados. Aqui, o processo de geração e uso do BeandEfinition está oculto nele. Este é o processo geral que realmente acontece dentro do COI:
classe pública simplesiocdemo {public static void main (string [] args) lança classNotFoundException {defaultListableBeanFactory beanFactory = new DefaultListableBeanFactory (); ResumoBeanDefinition mainModule = new RootBeandEfinition (mainmodule.class); AbstractBeanDefinition modulea = new RootBeandEfinition (DependeDModuleAimpl.class); AbstractBeanDefinition ModuleB = new RootBeAndEfinition (DependeDModuleBimpl.class); beanfactory.registerbeandEfinition ("mainmodule", mainmodule); BeanFactory.ReGisterBeandEfinition ("Modulea", Modulea); beanfactory.registerbeandEfinition ("Moduleb", ModuleB); MutablePropertyValues PropertSValues = new MutablePropertyValues (); PropertyValues.add ("Modulea", Modulea); PropertyValues.add ("Moduleb", ModuleB); mainmodule.setPropertyValues (PropertyValues); Módulo MainModule = (MainModule) BeanFactory.getBean ("MainModule"); Module.getModulea (). funcfrodulea (); Module.getModuleB (). FuncFroduleBeB (); }}Após o carregamento e a leitura das meta informações do XML, o mecanismo de análise do COI criará o módulo mencionado nele em uma beandefinição com base em seu tipo real. Essa defesa do BeaNDefinition pode ser considerada um processo de reflexão ou proxy. O objetivo é deixar o contêiner do COI limpar a estrutura do feijão do objeto de instância a ser criado no futuro e depois registrar essas estruturas de feijão no feijão e, em seguida, adicionar as dependências do módulo principal às propriedades do módulo principal do módulo de captação de fábrica, depois do registro, se o método do conjunto de setes ou o método de inicialização é fornecido pelo módulo principal.) tomou forma. Depois disso, basta chamar o método getBean para produzir os grãos que atendem aos requisitos. Esta é a próxima etapa do processo, e falaremos sobre isso mais tarde.
Depois de registrar as informações sobre o "desenho" da BeandEfinition para o Beanfactory, ainda podemos fazer alterações na concepção registrada. Este é um dos aspectos flexíveis do design da primavera para usuários mencionados anteriormente. Isso não significa que todos os processos sejam incontroláveis, mas deixa muito espaço para os usuários jogarem em muitos lugares. O método específico é usar o processador BeanFactory BeanFactoryPostProcessor para intervir no processamento do BeanFactory para reescrever ainda mais a parte do BeandEfinition que precisamos modificar. Esse processo corresponde ao processo de "pós-processamento" no processo.
Tomando um dos processadores comuns: atributo Processador de configuração de espaço reservado como exemplo, é processar o beanfactory registrado após a construção, de modo que o conteúdo no atributo de configuração do BeandEfinition correspondente seja modificado para as informações no arquivo de configuração do processador de configuração:
DefaultListableBeanFactory BeanFactory = new DefaultListableBeanFactory (); XmlBeandEfinitionReader Reader = new XMLBeanDefinitionReader (BeanFactory); Reader.LoadBeanCeandEfinitions (New ClassPathResource ("Beans.xml");); PropertyPlaceHoldConfigurer (); Configurer.SetLocation (New ClassPathResource ("About.Properties")); Configurer.PostProcesBeanFactory (BeanFactory);O beanfactoryPostProcessor processará o Beanfactory. O resultado é alterar alguns atributos definidos no BeandEfinition para algumas informações no local do BeanFactoryPostProcessor.
2. Estágio de instanciação de feijão
Sob a orientação dos "desenhos internos" processados da BeandEfinition, o contêiner pode transformar ainda mais o BeandEfiFnition em um objeto de instância ativado existente na memória através da reflexão ou da produção dinâmica de bytecode dinâmica e, em seguida, montar a injeção de dependência especificada pela BEANDefinition no objeto de instância criada pela injeção de detecção ou inicialização. Aqui, a referência do objeto de dependência é realmente atribuída aos atributos do objeto que precisam ser dependentes.
Mas deve -se notar aqui que a instância criada não é apenas uma instância simples da definição de feijão, mas uma instância de breta envolvida na primavera. Por que deve ser usado para embrulhar o feijão no método Beanwrapper? Porque o Beanwrapper fornece uma interface para acessar as propriedades do feijão uniformemente. Depois de criar a estrutura básica do feijão, as propriedades nela devem ser definidas. O método do setter de cada feijão é diferente, por isso será muito complicado se você o definir diretamente com a reflexão. Portanto, a Spring fornece a este invólucro para simplificar as configurações da propriedade:
Beanwrapper Beanwrapper = new BeanWrapperImpl (classe.ForName ("com.rocking.demo.mainmodule")); beanwrapper.setPropertyValue ("Modulea", Class.ForName ("com.rocking.demo.dpmoduleAmpl"). Class.ForName ("com.rocking.demo.depmodulebimpl"). NewInstance ()); mainModule mainModule = (mainmodule) beanwrapper.getwrapInstance (); mainmodule.getmodulea (). Funcroma (); mainmodule.get.getB ().O processo acima mostra que, na primavera, você pode entender a estrutura do feijão da instância que é embrulhado no futuro, obtendo o recipiente reflexivo da classe e fazendo a embalagem. Use o método de configuração de propriedade unificada setPropertyValue para definir propriedades para a instância deste pacote. A instância final do feijão obtida é obtida através do GetwrapInstance, e você pode descobrir que seus atributos foram atribuídos com sucesso.
No momento, a instância do feijão é realmente utilizável, mas a primavera também preparou estratégias flexíveis para nós no estágio de instanciação para concluir a intervenção do usuário nesse estágio. Semelhante ao BeanFactoryPostProcessor Control BeandEfinition na fase de inicialização de contêineres, durante o estágio de instanciação, a primavera fornece um processador de prostituto de beanPost para operar nas instâncias reunidas para completar possíveis mudanças:
Aqui está um exemplo para ilustrar que você define uma classe de implementação do BEANPOSTPROCESSOR, implementando os métodos pós -processadosfterinitialização e pós -processamento para a união para definir operações executadas separadamente após e antes da montagem da instância do feijão. Depois que o Beanfactory adiciona esse processador, cada vez que o método getBean montado, os dois métodos serão chamados na instância do feijão montada de acordo com o "desenho" (incluindo a instância dependente criada durante o processo de montagem). Esses métodos podem modificar essas instâncias de feijão.
Aqui está um exemplo como este (MainModule e suas dependências são as mesmas que anteriormente neste artigo):
classe Modulec {private string x; public string getx () {return x; } public void setx (string x) {this.x = x; }} classe ModulePostProcessor implementa o BEANPOSTProcessor {@Override public Object PostprocessaFterinitialization (objeto objeto, string string) lança beansexception {System.out.println (string); if (object Instânciaof Modulec) {System.out.println (string); (((Modulec) objeto) .setx ("depois"); } retornar objeto; } @Override Public Object PostProcessBeforeInitialization (objeto Objeto, String String) lança beansexception {if (objeto instância do modulec) {((modula) objeto) .setx ("antes"); } retornar objeto; }} classe pública é muito, lança o clastNotFoundException, o beansexception, InstantionException, BEANSEXCECTIONECCECTIONE, BEANSEXCECTION, NOVAFAULCESSEXCIONCE {DefaultListableBeanFactory XMLBeAndEfinitionReader Reader = new XMLBeandEfinitionReader (BeanFactory); Reader.LoadBeandEfinitions (New ClassPathResource ("Beans.xml")); ModulepospostProcessor Post Processor = new ModulepospostProcessor (); beanfactory.addbeanpostprocessor (pós -processador); Módulo MainModule = (MainModule) BeanFactory.getBean ("MainModule"); Modulec modulec = (Modulec) beanFactory.getBean ("Modulec"); System.out.println (modulec.getx ()); }}Este é o arquivo de configuração de dependência para o feijão:
<? xml versão = "1.0" coding = "utf-8"?> <Beans xmlns = "http://www.springframework.org/schema/beans" xmlns: xsi = "http:/wwww.w3 xsi: schemalocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans http://www.springframework.org/schema <propriedade name = "modulea"> <ref Bean = "Modulea"/> </Property> <propriedade name = "moduleb"> <ref Bean = "Moduleb"/> </Property> </bean> <bean id = "modulea"> <names name = "info"> <value> $ {modeaa.infoa} <Propriedade name = "Infob"> <Value> Informações do Moduleb </value> </Property> </bean> <bean id = "Modulec"> </shean> </ Beans>A partir do resultado final, podemos ver que cada vez que a instância getBean (inclusive gerada por dependências) obtida chamando o método getBean será recuperada pelo Processador BeanPosts para pré e pós-processamento.
Além do processamento, os grãos montados semelhantes ao processador de beanPosts acima, a primavera também pode definir funções de retorno de chamada para o processo de inicialização e destruição de feijões, configurando o init-method e o Method. Essas funções de retorno de chamada também podem oferecer flexibilidade a oportunidade de alterar as instâncias do feijão.
Todo o processo do COI da primavera é realmente o mesmo que o protótipo do COI que escrevemos para nós mesmos, exceto que o design complexo permite que o processo do COI forneça aos usuários espaço com mais flexibilidade e eficácia. Além disso, o COI da Spring também alcançou um design requintado em termos de segurança, estabilidade de contêineres e metadados à eficiência da conversão de feijão, tornando estável a base do COI, um recipiente de mola.