Prefácio
Este artigo apresenta principalmente o conteúdo relevante sobre o processo de inicialização do servlet e os princípios na inicialização da primavera. Não vou dizer muito abaixo, vamos dar uma olhada na introdução detalhada juntos.
Processo de inicialização e princípios:
1 Método de execução de inicialização do aplicativo de inicialização da primavera
StopWatch StopWatch = new StopWatch (); stopwatch.start (); ConfigurableApplicationContext context = null; Analisadores de Failureanalyzers = NULL; ConfigureheadlessProperty (); SpringApplicationRunListeners ouvintes = getRunListeners (args); ouvintes.starting (); tente {ApplicationArguments ApplicationArguments = new DefaultApplicationArguments (args); Ambiente Configurável de Ambiente de Ambiente = Preparação (ouvintes, ApplicationArguments); Banner PrintEdBanner = PrintBanner (Ambiente); // Crie um contexto ApplicationContext Container = CreateApplicationContext (); analisadores = novos falhas (contexto); PrepareContext (contexto, ambiente, ouvintes, ApplicationArguments, PrintDBanner); // Atualizar o contêiner do IOC refreshContext (contexto); AfterRefresh (contexto, ApplicationArguments); ouvintes.finished (contexto, nulo); stopwatch.stop (); if (this.logstartupinfo) {new startupInfologger (this.mainApplicationClass) .LogStard (getApplicationLog (), StopWatch); } retornar contexto; } Catch (ex -jogável ex) {HandlerUnfailure (contexto, ouvintes, analisadores, ex); lançar uma nova ilegalStateException (Ex); }2 CreateApplicationContext (): Crie um contêiner do IOC. Se for um aplicativo da web, crie um contêiner do IOC do AnoTationConfigEmbeddedWeBApplication. Caso contrário, crie um contêiner do COI do AnoTationConfigApplication.
public static final string default_context_class = "org.springframework.context." + "ANNOTATION.ANNOTATIONCONFIGAPplicationContext"; /** * O nome da classe do contexto do aplicativo que será usado por padrão para ambientes da Web *. */ Public Static Final String Default_Web_Context_Class = "Org.springFramework." + "boot.context.embedded.annotationConfigEmBeddedWebApplicationContext"; protected configurableApplicationContext createApplicationContext () {class <?> contextClass = this.ApplicationContextClass; if (contextClass == null) {tente {// Crie diferentes contêineres do IOC de acordo com o ambiente do aplicativo contextClass = class.ForName (this.webenvironment? Default_web_context_class: default_context_class); } catch (classNotFoundException ex) {THROW NOVA ILGLELGALSTATEEXCECCEIRA ("Não é possível criar um ApplicationContext padrão," + ", especifique um ApplicationContextClass", ex); }} return (configurableApplicationContext) beanutils.instantiate (contextClass); }3 RefreshContext (Contexto) A inicialização da mola atualiza o contêiner do IOC (crie objetos de contêiner, inicialize o contêiner e crie cada componente do contêiner)
private void refreshContext (ConfigurableApplicationContext Context) {Refresh (Context); if (this.registershutdowhook) {try {context.registerShutdowNhook (); } catch (accessControlexception ex) {// não permitido em alguns ambientes. }}}}4 refresh (contexto); Atualize o contêiner do COI que você acabou de criar
ApplicationChest de ApplicationContext Protected Void) {Assert.isInsinStanceOf (AbstractApplicationContext.Class, ApplicationContext); ((AbstractApplicationContext) ApplicationContext) .Refresh (); }5. Chame o método da classe pai ()
public void refresh () lança beansexception, ilegalStateException {objeto var1 = this.startupshutdownmonitor; sincronizado (this.startupshutdownmonitor) {this.PrepareRefresh (); ConfigurableListableBeanFactory BeanFactory = this.ObtainFreshBeanFactory (); this.PrepareBeanFactory (BeanFactory); tente {this.PostProcessBeanFactory (BeanFactory); this.invokeBeanFactoryPostProcessors (BeanFactory); this.RegisterBeanPostProcessors (BeanFactory); this.initMessagesource (); this.initapplicationEventMultiCaster (); this.onRefresh (); this.RegisterListeners (); this.finishBeanFactoryInitialization (BeanFactory); this.finishRefresh (); } catch (beansexception var9) {if (this.logger.iswarnenabled ()) {this.logger.warn ("Exceção encontrada durante a inicialização do contexto - cancelando a tentativa de atualização:" + var9); } this.Destroybeans (); this.cancelRefresh (var9); jogue var9; } finalmente {this.resetCommOncaches (); }}}6 O método OnRefresh da subclasse incorporadawebApplicationContext da classe pai abstrata abstratopplicationContext
@Override Protected void onRefresh () {super.onRefresh (); tente {createembeddedservletContainer (); } catch (throwable ex) {lança novo ApplicationContextexception ("Não é possível iniciar o contêiner incorporado", ex); }}7 No CreateEmbeddedservletContainer, a fábrica de contêineres incorporados será obtida e o servlet é criado a partir da fábrica de contêineres
private void CreateEmbedDedServLetContainer () {incorporadoServletContainer LocalContainer = this.EmbeddedservletContainer; ServletContext LocalServletContext = getServletContext (); if (localContainer == NULL && LocalServletContext == null) {// obtém contêiner de contêiner de servlet incorporado IncorporedServletLenerContainerFactory ContainerFactory = getEmbeddedServLetContainerFactory (); // Obtenha o recipiente de servlet incorporado correspondente com base na fábrica de contêineres. } else if (LocalServletContext! = null) {tente {getSeilinitializer (). OnStartup (LocalServletContext); } catch (servletexception ex) {tiro novo ApplicationContextexception ("Não é possível inicializar o contexto do servlet", ex); }} initPropertySources (); }8 Obtenha fábrica de contêineres de servlet do contêiner do IOC
// incorpeddedwebApplicationContext#getembeddedServletLearContainerFactory protegido EMBEDSERVENTEVELERCONTENERFABRATIVO GetembeddedServletContAinerFactory () {// Use nomes de bean para que não consideramos a hierarquia [] beanNames = getBeanFactory (). if (beannames.length == 0) {lança novo ApplicationContextexception ("Não é possível iniciar o incorporado WebApplicationContext devido à falta de" + "incorporado. } if (beannames.length> 1) {tire o novo ApplicationContextexception ("Incapaz de começar a incorporar WebApplicationContext devido a múltiplos" + "incorporados, feijões factadores:" + stringutils.arrayToCommadelimitedString (BeanNames)); } return getBeanFactory (). getBean (beanNames [0], incorporadoServletContainerFactory.class); }9 Use a fábrica de contêineres de servlet para obter recipientes de servlet incorporados. Qual fábrica de contêineres usar depende da dependência do ambiente de configuração
this.EmbeddedServLetContainer = containerFactory .getEmbeddedservletContainer (getSelfInitializer ());
10 O processo de criação acima inicia o contêiner do COI, depois inicia o contêiner incorporado e depois recupera os objetos restantes que não são criados no contêiner do IOC, como o controlador que você criou por você.
// instanciam todos os singletons restantes (não preguiçosos). finfactoryInitialização do final (BeanFactory);
Void protegido finalBeanFactoryInitialização (configurableListableBeanFactory BeanFactory) {// Inicialize o serviço de conversão para este contexto. if (beanfactory.containsbean (conversion_service_bean_name) && beanfactory.istypatch (conversion_service_bean_name, conversionservice.class)) {beanfactory.setConversionSerice (BeanFactory.getBean (conversion_Sonse_Bean_Name, Inversion, } // Registre um resolvedor de valor incorporado padrão se nenhum pós-processador de feijão // (como um bean do PropertyPlaceHoldConfigurer) registrou nenhum antes: // Neste ponto, principalmente para resolução nos valores de atributos de anotação. if (! BeanFactory.HasEmBedDedValueResolver ()) {beanFactory.addEmbeddedValueResolver (new StringValueResolver () {@Override public String resolvestringValue (String strval) {return getenviriMeM (). } // Inicialize o LoadTimeWeaverraware com antecedência para permitir o registro de seus transformadores mais cedo. String [] weaverrawarenames = beanfactory.getBeanNamesfortype (loadTimeweaverraware.class, false, false); para (string weaverrawarename: weaverrawarenames) {getbean (weaverrawarename); } // Pare de usar o carregador de classe temporário para correspondência de tipo. beanfactory.setTempClassLoader (null); // Permite o cache de todos os metadados da definição de feijão, sem esperar mais alterações. beanfactory.freezeconfiguration (); // instanciam todos os singletons restantes (não preguiçosos). beanfactory.preinstantiatesingLetons (); }Confira o método pré -InstantiatesingLetons
public void pré-InstantiatesingLetons () lança beansexception {if (this.logger.isdebugenabled ()) {this.logger.debug ("pré-instantando singletens em" + this); } List <string> beanNames = new ArrayList (this.beandEfinitionNames); Iterador var2 = beannames.iterator (); while (true) {while (true) {string beanname; RootbeandEfinition bd; faça {do {do {if (! var2.hasnext ()) {var2 = beannames.iterator (); while (var2.hasnext ()) {beanname = (string) var2.Next (); Objeto singletonInstance = this.getSingleton (beanname); if (instância singletonInstance de smartInitializingleton) {Final SmartInitializingingleton SmartSingleton = (SmartInitializingLeton) SingletonInstance; if (System.getSecurityManager ()! = NULL) {AccessController.Doprivileged (novo privilegiado <jection> () {public object run () {smartSingleton.AfterSingLetonsInsinAntiated (); Return null;}}, this.getCesContControlContextiated (); } else {smartSingleton.afteringLetonsInsinStantiated (); } } retornar; } beanname = (string) var2.Next (); bd = this.getMergedLocalBeandEfinition (beanname); } while (bd.isabstract ()); } while (! bd.issingleton ()); } while (bd.islazyinit ()); if (this.isfactoryBean (beanname)) {Final FactoryBean <?> Factory = (FactoryBean) this.getBean ("&" + beanname); boolean isogerinit; if (System.getSecurityManager ()! = NULL && Factory Instância de SmartFactoryBean) {isogerinit = ((boolean) accessController.Doprivileged (New PrivilegedAction <Oolean> () {public boolean run () {Return (SmartFactoryBean) Factory) () {public boolean Run () {Return (SmartFactoryBean)) this.getAccessControlContext ())). BooleanValue (); } else {isogerinit = instância de fábrica de smartFactoryBean && ((smartFactoryBean) fábrica) .IseaGerinit (); } if (isogerinit) {this.getBean (beanname); }} else {// registre bean this.getBean (beanname); }}}}}}}}}}Use o método getBean para criar todas as instâncias não criadas através da reflexão.
Usando recipientes de servlet incorporados:
Vantagens: simples, portátil
Desvantagens: o JSP não suporta por padrão, otimização e personalização são mais complicados
Etapas para usar um contêiner externo de servlet:
1. O projeto de guerra deve ser criado e a estrutura do diretório do projeto da Web da Jianhao é necessária.
2 Especificações de dependência incorporada do tomcat
3 Escreva uma subclasse da classe SpringBootSetLitializer e substitua o método de configuração
classe pública servletinitializer estende o springbootSertLeTIlitializer {@Override Protected SpringApplicationBuilder Configure (aplicativo SpringApplicationBuilder) {return Application.sources (Springboot04webjspApppplication.class); }}4 Inicie o servidor
A diferença entre o pacote inicial do jar e o pacote de guerra
JAR PACOTE: Execute o método de execução de SpringBootApplication, inicie o contêiner do COI e crie um contêiner de servlet incorporado
Pacote de guerra: Primeiro, inicie o servidor servlet, o servidor inicia o aplicativo Springboot (SpringbootSertletinitizer) e depois inicia o contêiner do COI
Regras do servlet 3.0+
1. Startup do servidor (startup de aplicativos da web), a instância do servletContainerlnitializer em todos os pacotes JAR no aplicativo Web atual será criada.
2 A implementação do servletContainerinitializer é colocada na pasta Meta-Inf/Serviços do pacote JAR
3 Você também pode usar a anotação @HandLestypes para carregar a classe especificada quando o aplicativo for iniciado.
Processo e princípios externos do tomcat
① Inicie o tomcat
② De acordo com as regras do servlet3.0+ descritas acima, você pode encontrar um arquivo chamado javax.servlet.servletLearContainerInitializer no módulo da web da primavera, e o conteúdo do arquivo é o org.springframework.web.sperServLearContainersitializer, que é usado para carregar o SperSvletLeartContializer.
③ Olhe para a definição de SpringServletContainerinitializer
@Handlestypes (WebApplicationInitializer.class) Classe public SpringServLetLeTonerinitializer implementa servletContainerInitializer { /** * delega o {@code servletContext} a qualquer {@link webApplicationInitializer} * implementações presentes no Application. * <p> Porque esta classe declara@{@code handlestypes (webApplicationInitializer.class)}, * servlet 3.0+ contêineres digitalizará automaticamente o caminho de classe para implementações * do {@code webAppinitial Inteface. * <p> se não {@code webApplicationInitializer} implementações forem encontradas no caminho de classe, * esse método é efetivamente um não-OP. Uma mensagem de log no nível de informações será emitida notificando * o usuário de que o {@code servletContainerInitializer} foi realmente chamado, mas que * não foram encontrados as implementações {@code webApplicationInitializer}. * <p> Supondo que um ou mais {@code webApplicationInitializer} sejam detectados, * eles serão instantados (e <em> classificados </em> se o@{@link * org.springframework.core.annotation.order @order} anotation estiver presente ou * the {@link ou org.sing.sring.sring.sPring.spring.spring.spring.ingfforming. Em seguida, o método {@link webApplicationInitializer#OnStartUp (servletContext)} * será chamado em cada instância, delegando o {@code servletContext} tais * que cada instância pode registrar e configurar servlets como o Spring * {@code DispatcherLear}, listers, como Spring, como o Spring * Componente como filtros. OnStartup (set <class <? >> webAppInitializerClasses, servletContext servletContext) lança servletexception {list <webApplicationInitializer> Initializers = new LinkedList <WebApplicationInitializer> (); {// deve defender: alguns contêineres do servlet nos fornecem classes inválidas, // não importa o que @HandleStypes diga ... if (! Waiclass.isinterface () &&! Modifier.isabstract (waiclassSignable.getModifiers () e webApplicationizer.class.isAsSignable. WebApplicationInitializer Tipos e adicionar aos Initiais da coleção.Add (WebApplicationInitializer) waiclass.NewInstance ()); Spring WebApplicationInitializer Tipos detectados no ClassPath "); retornar;} servletContext.log (Initializers.size () +" Spring WebAplicaçãoInitializers detectados no ClassPath "); AnnoTationAWareOrmEComParator.Sort (Initializers); // Chamando o MetododicationationArticationArticationArticationArticationArtionArtionArtionArtinizer (// // Chamando o ModhiApTicationArticationArtication (Initializer); Initializer.onstartup (ServletContext);No longo comentar acima, você pode ver que o SpringServletContainerInitializer passa por todas as classes do tipo de aplicativo Web anotado por @Handlestypes (WebApplicationInitializer.class) no parâmetro de conjunto do método OnStartup e cria instâncias para os tipos de aplicação da web por reflexão;
④ Método no final, cada implementação de aplicativo da Web chama seu próprio método OnStartup
⑤ WebApplicationInitializer possui uma classe de implementação abstrata SpringBootServletLitializer (lembre -se de que herdamos essa classe abstrata), e o método OnStartup de cada instância da WebApplicationInitializer (incluindo SpringBootStletLitializer) será chamada:
classe abstrata public abstrair SpringBootSertLetLitializer implementa WebApplicationInitializer {// Outro código ... @Override public void OnStartup (servletContext servletContext) lança servleTException {// Logger inicialização é diferida no caso de um ordenado // logServOnTIlTIlArtIlizer. // Crie o CONTENTIVO DE CONTENTIMENTO IOC IOC WebApplicationContext rootappContext = CRESEROOTAPplicationContext (ServletContext); if (rootappContext! = null) {servletContext.addlistener (novo contextLoaderListener (rootappContext) {@Override public void contextinitialized (evento servletContextevent) {// no-op porque o contexto do aplicativo já está inicializado}}}); } else {this.logger.debug ("Nenhum contextLoaderListener registrado, como" + "CreaterOpplicationContext () não" + "retornou um contexto de aplicativo"); }} WebApplicationCextionContext protegido CRESEROTAPplicationContext (ServletContext servletContext) {// Crie o Spring Application Builder e defina as propriedades relevantes SpringApplicationBuilder Builder = CreateSpringAppApplicationBuilder (); StandardServleTleNvironment Ambiente = New StandardServleNvironment (); Environment.InitPropertySources (ServletContext, NULL); construtor.ENVIRILIMENT (Ambiente); construtor.Main (getClass ()); ApplicationContext parent = getExistingrootwebApplicationContext (servletContext); if (pai! = null) {this.logger.info ("contexto raiz já criado (usando como pai)."); servletContext.SetAttribute (webApplicationContext.root_web_application_context_attribute, null); builder.initializers (new ParentContextApplicationContextInitializer (Parent)); } builder.initializers (new servletContextApplicationContextInitializer (servletContext); builder.contextClass (anotaçãoConfigembeddedwebApplicationContext.class); // Depois de chamar o método de configuração e criar um projeto da Web do tipo de guerra, uma vez que a subclasse do SpringBootStletinitializer substitui o método de configuração, o método de configuração que definimos substituídos é chamado aqui. Construtor = configure (construtor); // Um aplicativo de primavera é construído através do aplicativo SpringApplication do construtor = Builder.Build (); if (Application.getSources (). isEmpty () && AnoTationUtils .Findannotation (getClass (), Configuration.class)! = null) {Application.getSources (). Add (getClass ()); } Assert.State (! Application.getSources (). IsEmpty (), "Nenhuma fontes de aplicação de primavera foi definida. Substitua o método de configuração" + "ou adicione uma anotação @configuration"); // Verifique se as páginas de erro são registradas se (this.ReGisterErRorPageFilter) {Application.getSources (). Add (errorPageFilterConfiguration.class); } // Iniciar o aplicativo Spring Return Run (aplicativo); } // O aplicativo Spring é iniciado, cria e retorna o contêiner do COTENER IOC Protected WebApplicationContext Run (SpringApplication Application) {return (webApplicationContext) Application.run (); }}Quando a instância do SpringBootSetLetIlitializer executar o método OnStartup, o método RUN será executado através do método CreateroTapplicationContext. O próximo processo é o mesmo que o processo de execução do aplicativo iniciado na forma de um pacote JAR. O contêiner do COI será criado internamente e devolvido. No entanto, o aplicativo na forma de um pacote de guerra não criará mais o contêiner do servlet durante o processo de criação do contêiner do IOC.
Resumir
O acima é o conteúdo inteiro deste artigo. Espero que o conteúdo deste artigo tenha certo valor de referência para o estudo ou trabalho de todos. Se você tiver alguma dúvida, pode deixar uma mensagem para se comunicar. Obrigado pelo seu apoio ao wulin.com.