Récemment, j'ai examiné le code source de Spring et je me suis soudainement demandé comment Spring a commencé la sienne sans configuration Web.xml. Compte tenu de la capacité limitée et la première fois que j'ai lu le code source et publié un blog, pardonnez-moi si je ne sais pas quoi faire ~
L'idée IDE est IntelliJ Idea, qui est plus facile à lire le code source que MyEclipse, et je l'aime beaucoup dans l'arrière-plan noir. Ensuite, le projet est exécuté sous le plugin Maven Tomcat7. La version de printemps est 4.3.2.release.
Si vous avez écrit un Web Spring avec une configuration d'annotation pure, vous devez savoir que vous devez hériter d'une classe d'initialisation pour charger le bean, puis nos fonctions et haricots personnalisés seront chargés à partir de cette classe. Vous trouverez ci-dessous l'un de mes webinitialiseurs
@Order (1) la classe publique WebMvCINIT étend AbstractAnnotationConfigDispatcherServletInitializer {Protected class <?> [] GetrootConfigClasses () {return new class [] {rootConfig.class, WebSecurityConfig.class}; } class protégé <?> [] getServletConfigClasses () {return new class [] {webConfig.class}; } string protégé [] getServletMappings () {return new String [] {"/"}; } @Override Protected Filter [] getServletFilters () {return new Filter [] {new HiddenHttpMethodFilter ()}; }}Tout d'abord, regardez la structure de la classe AbstractannotationConfigDispatcherServitializer. Il s'agit également d'une fonction UML de l'idée. Cliquez avec le bouton droit sur les diagrammes-> Afficher les diagrammes dans la classe.
Ensuite, nous cliquons directement sur AbstractAnnotationConfigDispatcherserServitializer. Vous pouvez voir que cette classe est très simple, avec seulement quatre méthodes. Ensuite, nous faisons attention à CreaterootApplicationContext ()
@Override Protected webApplicationContext CreaterootApplicationContext () {class <?> [] ConfigClasses = getrootConfigClasses (); if (! ObjectUtils.Isempty (configClassmes)) {annotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext (); rootAppContext.Register (configClasses); return rootAppContext; } else {return null; }}Cette méthode signifie approximativement d'obtenir lesclasses envoyées par l'utilisateur (programmeur), puis d'enregistrer les haricots. Ce ne sont pas ce qui nous préoccupe, mais cette méthode devrait être exécutée après le démarrage, nous pouvons donc rechercher cette méthode
Sous l'idée, Ctrl + G peut trouver une méthode ou une classe à appeler, puis définir la plage de recherche sur le projet et la bibliothèque
Nous avons constaté que la méthode RegisterContextLoaderListener (ServletContext ServLetContext) sous AbstractContextloaderinitializer appelle le CreaterootApplicationContext () de la sous-classe pour obtenir le WebApplicationContext, et continuez à trouver l'appelant de la méthode RegisterContextLoDoDerListener (ServletContext ServletContext). En conséquence, il est constaté que c'est le startup (ServletContext ServletContext) dans cette classe. La classe AbstractContextLoDerinitializer est publiée ci-dessous.
Classe abstraite publique AbstractContextLoDerinitializer implémente WebApplicationInitializer {/ ** Logger disponible pour les sous-classes * / Protected Final Log Logger = LogFactory.getLog (GetClass ()); @Override public void onStartup (servletContext servletContext) lève Servlexception {registreContextLogerListener (servletContext); } / ** * Enregistrez un {@Link ContextLoDoListener} par rapport au contexte de servlet donné. Le * {@Code ContextLoaderListener} est initialisé avec le contexte d'application renvoyé * à partir de la méthode du modèle {@link #createrootapplicationcontext ()}. * @param servletContext Le contexte du servlet pour enregistrer l'écouteur contre * / protégé void registerContextLoaderListener (servletContext ServletContext) {webApplicationContext rootAppContext = CreaterootApplicationContext (); if (rootAppContext! = null) {contextloadherListener écouteur = new ContextLoaderListener (rootAppContext); auditeur.setContextInitializers (getrootApplicationContextInitialisers ()); ServletContext.AddListener (écouteur); } else {Logger.debug ("Aucun contexteListener enregistré, en tant que" + "CreaterootApplicationContext () n'a pas renvoyé de contexte d'application"); }} / ** * Créez le contexte d'application "<strong> root </strong>" à fournir au * {@code contextloadherListener}. * <p> Le contexte renvoyé est délégué à * {@Link ContextLoaderListener # contextloadherListener (webApplicationContext)} et sera * établi comme contexte parent pour tout contexte {@code dispatcherservlet} application *. En tant que tel, il contient généralement des services de niveau intermédiaire, des sources de données, etc. * @return le contexte de l'application racine, ou {@code null} Si un contexte racine n'est pas * souhaité * @see org.springframework.web.servlet.support.abstractDispatcherServletInitializer * / Protected abstractApcationContext CreateroTOtApplicationContex / ** * Spécifiez les initialiseurs de contexte d'application à appliquer au contexte de l'application racine * avec laquelle le {@code contextloadherListener} est créé. * @Since 4.2 * @see #createrootApplicationContext () * @SEE ContextLoaderListener # setContextInitialisers * / Protected ApplicationContexInitializer <?> [] GetrootApplicationContexInitialisers () {return null; }}Notez que nous avons sauté la classe abstraite AbstractDispatcherServitializer (voir le diagramme UML). Cette classe configure principalement Dispatcherservlet, qui est l'implémentation de Spring MVC et d'autres fonctions.
Ensuite, qui chargera le RésuméContextloaderinitializer? WebApplicationInitializer est déjà une interface, et il n'y aura pas de classe abstraite à l'appeler. J'ai donc essayé de rechercher l'interface WebApplicationInitializer. Parce que les grands projets comme le printemps sont définitivement orientés vers l'interface, l'appel est généralement écrit à l'interface. Ensuite, nous avons trouvé la classe SpringservletContainerinitializer, qui implémente l'interface de servletContainerinitializer. Cette classe signifie probablement démarrer tous les applications Websitialiseurs. On peut dire que cette classe est très proche de notre objectif. Vous trouverez ci-dessous le SpringservletContainerinitializer
@Handlestypes (WebApplicationInitializer.Class) Classe publique SpringservletContainerinitializer implémente ServletContainerinitializer {@Override public void onStartup (set <class <?> WebAppinitializercLasses, ServletContext ServletContex) LinkedList <WebApplicationInitializer> (); if (webAppinializerclasses! = null) {for (class <?> waiclass: webAppinializerclasses) {// être défensif: certains conteneurs de servlets nous fournissent des classes invalides, // peu importe ce que @handlestypes dit ... if (waiclass.getModIfiers () &&! Modifier.isabstract WebApplicationInitializer.class.IsAssignableFrom (waiclass)) {try {initialisers.add ((webApplicationInitializer) waiclass.newinstance ()); } catch (Throwable ex) {Throw New Servlexception ("Échec de la classe WebApplicationInitializer Web", ex); }}}}} if (initialisers.isempty ()) {servletContext.log ("pas de types WebApplicationInitializer les types détectés sur classpath"); retour; } servletContext.log (initialisers.size () + "Spring WebApplicationInitialisers détecté sur ClassPath"); AnnotationAwareOrderComparator.Sort (initialiseurs); for (WebApplicationInitializer initializer: initialisers) {initializer.OnStartup (servletContext); }}}Dans le dernier foreach, démarrez tous les applications Websitialiseurs. La question est donc de savoir qui commencera SpringservletContainerinitializer? Spring ne pourra certainement pas le démarrer par lui-même.
Dans l'environnement Web, il n'y a que des conteneurs Web. Nous pouvons faire un point de rupture dans l'un des endroits ci-dessus, puis le déboguer (en fait, nous pouvons complètement déboguer = = tout au long du processus, ce qui est précis et rapide, mais cela n'a pas la signification de la recherche, et le paysage le long de la route est assez bon)
Vous pouvez voir la méthode startInternal de la classe StandardContext sous le package org.apache.catalina.core. Ceci est déjà dans la portée de Tomcat, donc notre objectif a été atteint. Notez que l'interface servletContainerinitializer n'est pas sous le package à ressort, mais est javax.servlet
Je suppose que Tomcat utilise l'interface servletContainerinitializer de javax.servlet pour trouver les classes qui implémentent cette interface dans le conteneur, puis appellent leur startup, puis SpringservletContainitializer peut démarrer tous les applications WebInitialiseurs, qui contient le Webinitializer que nous avons écrit nous-mêmes. De plus, Spring Security est également configuré avec l'annotation pour implémenter WebApplicationInitializer, donc Spring est très extensible. Examinons le code source Tomcat dans les prochains jours pour comprendre le mécanisme Tomcat.
Ce qui précède est tout le contenu de cet article. J'espère que cela sera utile à l'apprentissage de tous et j'espère que tout le monde soutiendra davantage Wulin.com.