Na classe Java, um grande homem chamado Rod Johnson descobriu que o desenvolvimento inicial do Java Enterprise no nível da empresa estava em um estado caótico.
Por isso, decidiu escrever uma infraestrutura geral que poderia resolver problemas.
Porque acredita firmemente que a programação orientada à interface pode minimizar as alterações, mas também facilitar a expansão e a mudança. Então, ele escreveu a seguinte interface.
A primeira coisa a criar em um estado caótico é a mãe de todos os objetos, o Beanfactory e, com ele, você pode obter todos os objetos e atribui -lo, ou seja, antes de tudo, Gaia - a mãe da terra.
Com a mãe original, Johnson pensou, e se eu quisesse obter um conjunto de objetos de feijão em vez de apenas um ou vários? Além disso, e se o filho da mãe também quiser dar à luz um parceiro? Portanto, Johnson criou listableBeanFactory para operar um conjunto de objetos de feijão. Por exemplo, o getBeansOftype pode obter um conjunto de feijões do mesmo tipo com base nele; criou hierárquicos factivos para resolver os problemas hierárquicos de múltiplos beanfactory, como o GetParentBeanFactory pode obter a fábrica pai do Beanfactory.
Esse feijão é usado em um aplicativo, portanto o BeanFactory precisa ter a capacidade de mover em um aplicativo. No Beanfactory, você só precisa considerar comportamentos relacionados a feijões, como obter feijão, tipo de feijão, etc.; E se você deseja fornecer a eles habilidades no aplicativo, precisa considerar mais, como o nome do aplicativo, o tempo de inicialização, o ID, etc. Comportamentos e atributos relacionados ao próprio aplicativo, então Johnson pensou em criar um ApplicationContext. Johnson achou que esse ApplicationContext deveria ser capaz de fazer muitas coisas, e deve ser capaz de lidar com informações de texto parametrizadas e internacionalizadas, por isso adiciona a interface MessageRce; Ele deve ser capaz de publicar eventos para desacoplar os componentes, por isso possui a interface ApplicationEventPublisher; Ele deve ser capaz de obter arquivos de recursos, para ter a interface RecursondatternResolver; Ele deve ser capaz de ter diferentes objetos de processamento em diferentes ambientes, para que tenha a interface do ambiente.
ApplicationContext herda todas essas interfaces.
Mas o mais importante é que o Beanfactory e o ApplicationContext precisam ter recursos configuráveis, para que existam sub-interfaces ConfigurableBeanFactory e ConfiguRableApplicationContext; Além disso, a Web era uma tendência muito importante naquele momento e era um pouco única em comparação com outros aplicativos, por isso precisava obter o ServletContext, então havia o WebApplicationContext.
Até agora, Johnson tem pensado abstrato sobre o comportamento da interface e não os implementou em detalhes.
Olhando para o Beanfactory e o ApplicationContext criado, Johnson percebeu que o trabalho do dia estava longe de terminar porque não havia solução real para como fazer todo o sistema funcionar, então Johnson começou a pensar em como implementá -los.
A primeira coisa que Johonon pensa é em que capacidades essa implementação deve ter? Obviamente, precisamos incluir o AutowirecapableBeanFactory, listableBeanFactory e ConfigurableBeanFactory mencionado anteriormente. Portanto, o configurableListableBeanFactory foi criado. Em segundo lugar, várias habilidades para objetos de feijão precisam ser consideradas, uma é a capacidade de alias; O segundo é a capacidade de salvar objetos de singleton; O terceiro é a capacidade de armazenar em cache; Eles são implementados na classe SimleAliasRegistry, na classe PadringLetonBeanRegistry e da classe FactoryBeanRegistrySupport, respectivamente.
Finalmente, foi criado o DefaultListableBeanFactory, que é o protótipo de todas as fábricas do COI na primavera e é o primeiro filho real do Beanfactory. Essa criança é muito importante e se tornou a base para a criação independente de contêineres do COI. Se for estendido e usado, a maioria deles é herdada ou usada em combinação.
Se você deseja inicializar um DefaultListableBeanFactory, pode usar o seguinte código
ClassPathResource res = new ClassPathResource ("ApplicationContext.xml"); DefaultListableBeanFactory f = new DefaultListableBeanFactory (); XMLBeAndEfinitionReader R = novo XMLBeandEfinitionReader (f); r.loadbeandEfinitions (res); Em seguida, Johnson achou que o Beanfactory tem uma implementação padrão relativamente abrangente, e e o ApplicationContext? Assim, Johnson criou incansavelmente três implementações importantes do ApplicationContext: filesystemxmlapplicationContext, ClassPathXMLApplicationContext, AnoTationConfigWebApplicationContext (na verdade, existem muito mais, como manusear portlets e lidar com redes)
A primeira coisa que Johnson considera é como fazer o processo de inicialização da primavera. Ele deve ser colocado em um nível relativamente abstrato, para que todas as classes no nível mais baixo possam ser reutilizadas. Então, ele implementou o ConfigurableApplicationContext usando um abstractApplicationContext. Há também uma função muito importante, ou seja, carregando um arquivo na forma de um recurso, que requer abstrair o recurso em uma classe de recursos e abstrair a implementação específica do recurso de posicionamento para o ResourceLoader. AbstractApplicationContext também precisa herdar o DefaultResourceLoader para fornecer essa função. AbstractApplicationContext concluiu todo o processo de inicialização (Deus o organizou para ser concluído no dia seguinte), mas não administrou o Beanfactory. Portanto, sua subclasse abstractrefreshableAplicationContext faz isso especificamente, implementando o refreshBeanFactory, CloseBeanFactory, getBeanFactory gerencia especificamente o ciclo de vida dos beanfactormos, mas abstractrefreshableApplicationContext ainda não carrega todos os beanos. Onde carregar os recursos configurados, na verdade, ele vai para a subclasse mais baixa para fazê -lo, como o FileSystemxMLApplicationContext, que é ler um XML ApplicationContext para o sistema de arquivos; ClassPathXMLApplicationContext é ler este ApplicationContext para o caminho de carregamento da classe. AnnoTationConfigWebApplicationContext carrega feijões da anotação do arquivo de classe, e a varredura da mola começa a partir de agora.
Vendo que o quadro principal havia sido estabelecido, Johnson adormeceu com satisfação com um sorriso.
No primeiro dia, Johnson completou uma estrutura geral da primavera.
No segundo dia, Johnson estava se preparando para realmente lidar com os problemas anteriores. Por exemplo, o processo de inicialização do contêiner da mola. Como mostrado na figura, Johnson divide esse processo em muitos subprocessos, que estão todos trabalhando em torno do grande objetivo de carregar feijões.
Esse processo é colocado no método de atualização no abstrateApplicationContext. O código é o seguinte: Johnson divide o processo de atualização em muitos subprocessos, e esses subprocessos estão no mesmo nível abstrato. Essa maneira de escrever é dar às gerações futuras um modelo.
public void refresh () lança beansexception, ilegalStateException {sincronizado (this.startupshutdownmonitor) {// Prepare esse contexto para refrescar. preparerefresh (); // Diga à subclasse para atualizar a fábrica de feijão interna. ConfigurableListableBeanFactory BeanFactory = obtinFreshBeanFactory (); // Prepare a fábrica de feijão para uso neste contexto. prepararBeanFactory (BeanFactory); tente {// permite pós-processamento da fábrica de feijões nas subclasses de contexto. PostprocessBeanFactory (BeanFactory); // Invoca os processadores de fábrica registrados como feijões no contexto. InvokeBeanFactoryPostProcessors (BeanFactory); // Registre processadores de feijão que interceptam a criação de feijões. RegisterBeanPostProcessors (BeanFactory); // Inicialize a fonte da mensagem para este contexto. initMessagesource (); // Inicialize o multicaster do evento para este contexto. initApplicationEventMultiCaster (); // Inicialize outros grãos especiais em subclasses de contexto específicas. onRefresh (); // Verifique se há feijões ouvintes e registre -os. RegisterListeners (); // instanciam todos os singletons restantes (não preguiçosos). finfactoryInitialização do final (BeanFactory); // Última etapa: publique o evento correspondente. finalizeRfresh (); } catch (beansexception ex) {// Destrua Singletons já criados para evitar recursos pendurados. DestroyBeans (); // Redefinir sinalizador 'ativo'. cancelrefresh (ex); // propaga a exceção ao chamador. jogar ex; }}} Se você olhar para um nível superior, esses processos realmente giram em torno de vários aspectos: 1. Atualizar o ciclo de vida; 2. Inicialização e preparação do Beanfactory; 3. Gere e registre o BeandEfinition; 4. Pós -processador de Beanfactory; 5. Defina mensagens, eventos e ouvintes.
1. Ciclo de vida refrescante
PrepareRefresh, esse processo registra principalmente o log e indica que a primavera iniciou, inicializa os recursos da propriedade (como inicializar alguns recursos no Serlvet) e verificar os recursos da propriedade (como escrever apenas chave sem valor).
OnRefresh, o objetivo é fornecer alguns aplicativos especiais, para que eles possam expandir durante o processo de atualização. A maior parte do uso atual é definir o tema para o contexto do aplicativo para servlet
Finalizador de finalização, faça alguns trabalhos de acabamento, como inicializar o LifecycleProcessor, o final de publicação para a atualização, etc.
CancelRefresh, altera principalmente o estado atual para não ativo quando ocorre uma exceção.
2. Inicialização e preparação do BeanFactory
Johnson acha que devemos deixar a carga do Beanfactory e registrar o feijão de forma transparente quando inicializada, para que meu encapsulamento seja muito bem -sucedido para o mundo exterior, então essa etapa realmente faz muitas coisas. A figura a seguir omite muitas etapas e lista apenas os principais pontos.
AbstractApplicationContext chamará o refreshBeanFactory. Ele primeiro verificará e fechará o BeanFactory existente, depois criará um novo BeanFactory e, em seguida, usará essa fábrica para carregar todas as partes do BeaNDefinition.
Entre eles, o LoadBeandEfinitions será entregue a subclasses para diferentes implementações. Por exemplo, o abstractxmlapplicationContext é lido principalmente no XML; A implementação do AnoTationConfigWebApplicationContext chamará o scanner para digitalizar os grãos da classe.
3. Gere e registre o BeandEfinition
Após analisar a configuração XML, o método ParsedefaultElement do DefaultBeandEfinitionDocumentReader executará o processamento correspondente com base nos elementos no XML. Entre eles, ao encontrar um elemento de feijão, o método RegisterBeandEfinition no BeandEfinitionReaderutils será finalmente chamado. O parâmetro aprovado neste método é o BaNDefinitionRegistry, que na verdade chama de volta o método RegisterBeandEfinition do DefaultListableBeanFactory para registrar o BeandEfinition (DefaultListableBeanFactory implementa BeandEfinitionRegistry).
4. Pós -processador de Beanfactory
O pós -processador Beanfactory é uma maneira fornecida pela primavera para permitir que suas subclasses sejam flexíveis. Existem 2 etapas na primavera: PostprocessBeanFactory, InvokeBeanFactoryPostProcessors. RegisterBeanPostProcessors instanciam e chamam todos osprocessadores de beanPosts, que são usados para expandir o feijão antes e após a inicialização do feijão.
5. Configure mensagens, eventos e ouvintes
Defina a fonte de mensagem padrão para DelegatingMessagesource. Se já houver um MensagemRce na fábrica, use essa fonte de mensagens. O multicaster de evento é simplificadorevplicationEventMultiCaster. Se já houver um ApplicationEventMultiCaster na fábrica, use este ApplicationEventMultiCaster e registre todos os ouvintes de aplicativos para receber eventos.
O MessageRce é um método importante para arquivos de recursos internacionais. A primavera suporta fontes de mensagens no ApplicationContext.
A Spring fornece a implementação padrão do MessageRce, usando java.util.resourcebundle para extrair mensagens. A primavera pode acessar diretamente a mensagem do ApplicationContext.getMessage () configurando um feijão com um ID especial como mensagens e definindo o nome do arquivo de i18n. Se no JSP, você também poderá acessar a mensagem através da tag Spring: Mensagem.
Evento: os eventos são um mecanismo de desacoplamento relativamente importante. A primavera o introduziu no principal aplicativoContext. Seu princípio é relativamente simples. Por um lado, o gerador de eventos pode enviar eventos; Por outro lado, parece que o ouvinte do evento pode responder aos eventos. A implementação específica basicamente mantém uma coleção de ouvintes de eventos no gerador e "registro" (ou seja, participe) de todos os ouvintes desta coleção de ouvintes de eventos.
Na primavera, o ApplicationContext é usado como gerador de eventos, o ApplicationListeners são usados como coleção do ouvinte e o ApplicationEventMultiCaster é usado para publicar eventos.
Várias etapas para publicar um evento:
Assinatura: inicialmente addApplicationListener à coleção do ouvinte.
Publicar: ApplicationContext herda o ApplicationEventPublisher, implementando o PublishEvent. Este método atravessará primeiro a coleção ApplicationListeners deste ApplicationContext, ligará para o OnApplicationEvent para cada ouvinte, para que cada ouvinte seja notificado; Após a conclusão desta etapa, o mesmo evento será publicado para todos os ApplicationListeners do pai ApplicationContext.
A publicação de eventos é muito comum. Nossos próprios aplicativos não apenas podem usar essa publicação de eventos, mas a estrutura da primavera em si também está usando a publicação de eventos. Aqui estão algumas aplicações de eventos na primavera:
O contextrefreshedEvent será publicado no FINALRefresh para indicar que a atualização termina e notifica o ouvinte. No ApplicationContext, os métodos de início e parada publicarão eventos que indicam o início ou o fim do contexto.
Depois que Johnson criou a estrutura principal e o processo de operação da primavera, ele descobriu que a primavera fornece muitos locais de expansão flexíveis. Então Johnson está se preparando para anunciar esse uso flexível de expansão no terceiro dia.
1. BeanPostProcessor. O BeanPostProcessor fornece uma interface de extensão após a conclusão da criação do feijão. Quando você precisa fazer algum processamento no feijão após o criado, o BeanPostProcessor é o método preferido.
2. Ciente. O feijão injetado precisa conhecer algumas partes de seu recipiente. A primavera completa os retornos de chamada através do consciente, como o Beannameaware, que permite que o feijão saiba seu nome. O BeanFactoryAware pode permitir que o feijão compreenda o Beanfactory, ApplicationContextAwe, que permite que o feijão opere o ApplicationContext. Dessa forma, o feijão injetado com a primavera pode fazer uma ampla gama de coisas.
Para a extensão do BEANPOSTPROCESSOR, a própria Spring tem um exemplo de como identificar um feijão consciente. O feijão consciente é um feijão relativamente especial e a primavera requer alguns atributos adicionais. Então, como a primavera será usada para o processo de injeção? De fato, a primavera não o escreve no processo de processamento principal, mas coloca -o no ApplicationContextAwareProcessor, no BeanPostProcessor e, finalmente, invocou interfaces para determinar o tipo de feijão e injetar atributos correspondentes. Essa abordagem usa o BeanPostProcessor para concluir outro uso prolongado, que é realmente excelente.
private void InvoKeawareInterfaces (objeto Bean) {if (bean instância do consciência) {if (bean instanceof AmbientAware) {((AmbientalAcare) Bean) .setenvironment (this.ApplicationContext.getEnvironment ()); } if (instância do feijão de incorporadoValueResolverrage) {((incorporadoValueResolverrage) Bean) .setEmededDedValueResolver (new IncleddedValueResolver (this.ApplicationContext.getBeanFactory ()); } if (bean instanceof ResourceLoaderaWare) {((ResourceLoaderaWare) Bean) .SetResourceLoader (this.ApplicationContext); } if (bean instanceOf ApplicationEventPublisheRaWare) {((ApplicationEventPublisheRaWare) Bean) .SetApplicationEventPublisher (this.ApplicationContext); } if (bean instanceOf messensourCeaware) {((messageRceaware) bean) .SetMessagesource (this.ApplicationContext); } if (bean instanceOf ApplicationContexTAWee) {((ApplicationContexTAWe) Bean) .SetApplicationContext (this.ApplicationContext); }}}Existem mais regras para usar consciência. Por exemplo, o código a seguir pode perceber o ApplicationContext. Depois que a primavera cria esse feijão, ele injetará o ApplicationContext, para que possamos usar esse contexto para concluir a publicação de eventos.
classe pública Hellobean implementa ApplicationContexTAWe {private ApplicationContext ApplicationContext; String privada helloword = "Olá! Mundo!"; public void setApplicationContext (ApplicationContext context) {this.ApplicationContext = Context; } public void Sethelloword (String helloword) {this.helloword = helloword; } public string gethelloword () {ApplicationContext.publishEvent (new PropertyGettedEvent ("[" + helloword + "] está gotado")); retornar helloword; }} 3. BeanFactoryPostProcessor, este pós -processador é geralmente usado para lidar com a interface estendida criada pelo BeanFactory. Um exemplo é o seguinte. Depois de injetar este feijão, ele imprimirá automaticamente o número de feijões injetados após a criação do Beanfactory:
classe pública BeanCounter implementa beanfactoryPostProcessor {@Override public void postprocessBeanFactory (configurableListableBeanFactory BeanFactory) lança beansexception {System.out.println (BeanFactory.getbeendEnitionCount ()); }} 4. FactoryBean. A FactoryBean é um feijão especial, que permite a injeção em recipientes de mola e gerando feijões reais, para que possa ser definido dessa maneira. A própria fábrica é um feijão, que tem a capacidade de fornecer feijão. O seguinte começa com a chamada de fábrica e fala sobre como a primavera usa esse feijão.
Para distinguir entre feijões comuns e fábricas, a primavera também deve ter um processo de julgá -los e lidar com eles especialmente. Este processo está no GetObjectForBeanInstance of AbstractBeanFactory
Objeto protegido GetObjectForBeanInstance (objeto BeanInstance, Nome da String, String Beanname, RootBeandEfinition MBD) {// Não deixe o Código de Chamada tente desreferenciar a fábrica se o feijão não for uma fábrica. if (beanfactoryutils.isfactoryDereference (nome) &&! (BeanInstance Instância de FactoryBean)) {tire o novo beanisnotaFactoryException (transformEdBeanName (nome), beanInstance.getclass ()); } // Agora temos a instância do feijão, que pode ser um feijão normal ou uma fábrica. // Se for um FactoryBean, usamos -o para criar uma instância de feijão, a menos que o // Caller realmente queira uma referência à fábrica. if (! (BeanInstance Instância do FactoryBean) || BeanFactoryutils.isfactoryDereference (nome)) {return beanInstance; } Objeto objeto = null; if (mbd == null) {object = getCachedObjectForFactoryBean (beanname); } if (object == null) {// retorna a instância do feijão da fábrica. FactoryBean <?> Factory = (FactoryBean <?>) BeanInstance; // Objeto de caches obtidos do FactoryBean se for um singleton. if (mbd == null && containsbeandEfinition (beanname)) {mbd = getMergedLocalBeandEfinition (beanname); } boolean sintético = (mbd! = null && mbd.issynthetic ()); objeto = getObjectFromFactoryBean (Factory, Beanname ,! Sintético); } retornar objeto; } Pode -se observar que, se for um feijão comum, será devolvido diretamente e, se for um FactoryBean, a chamada final chamará o Factory.getObject para retornar o objeto específico. Se você pensa em toda a primavera como uma fábrica abstrata e ao produzir grãos abstratos, a FactoryBean é uma fábrica específica que produz os objetos que você precisa.
Existem muitos usos do FactoryBean na primavera. Para dar um exemplo relativamente comum, ao integrar o Factory Session of Hibernate, o local de fábrica local é geralmente injetado, mas essa fábrica de sessão não é na verdade não é um feijão comum. Ele pode ser produzido simplesmente injetando -o no arquivo de configuração. Possui muitas peças personalizadas, então a Spring faz deste feijão uma fábrica e controla seu objeto de produção.