Recientemente, miré el código fuente de la primavera y de repente me pregunté cómo la primavera comenzó sin configuración web.xml. Dada la capacidad limitada y la primera vez que leí el código fuente y publiqué un blog, perdóname si no sé qué hacer ~
El IDE que uso es la idea IntelliJ, que es más fácil leer el código fuente que MyEClipse, y me gusta mucho en el fondo negro. Luego, el proyecto se ejecuta bajo el complemento Maven Tomcat7. La versión de primavera es 4.3.2. Release.
Si ha escrito una red de primavera con configuración de anotación pura, debe saber que necesita heredar una clase de inicialización para cargar el bean, y luego nuestras funciones y frijoles personalizados se cargarán desde esta clase. A continuación se muestra uno de mis webinicializadores
@Order (1) La clase pública WebMVCinit extiende AbstractAnnotationConfigDispatcherServletInitializer {clase protegida <?> [] GetRootConfigClasses () {return new class [] {rootConfig.class, WebSeCurityConfig.class}; } clase protegida <?> [] getServletConfigClasses () {return new class [] {webconfig.class}; } cadena protegida [] getServletMappings () {return new String [] {"/"}; } @Override Protected Filter [] getServletFilters () {return new Filter [] {new HiddenHttpMethodFilter ()}; }}Primero, mire la estructura de la clase ANCRESSAnTationConfigDispatcherservletinitializer. Esta es también una función UML de la idea. Diagramas de clic derecho-> Mostrar diagramas en la clase.
Luego hacemos clic directamente en AbstractAnnotationConfigDispatcherServletinitializer. Puede ver que esta clase es muy simple, con solo cuatro métodos. Luego prestamos atención a CreaterotapplicationContext ()
@Override WebApplicationContext CreaterOtApplicationContext () {class <?> [] ConfigClasses = getRootConfigClasses (); if (! ObjectuTILLS.ISEMPTY (configClasses)) {AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext (); RootAppContext.Register (configClasses); return rootAppContext; } else {return null; }}Este método significa aproximadamente obtener las clases de raíz enviadas por el usuario (programador) y luego registrar los frijoles. Esto no es lo que nos preocupa, pero este método debe ejecutarse después del inicio, por lo que podemos buscar desde este método
Bajo idea, Ctrl+G puede encontrar un método o clase para llamar, y luego establecer el rango de búsqueda en el proyecto y la biblioteca
Descubrimos que el método RegisterContextLoLoCerListener (ServletContext ServletContext) en ResumenContextLoLoaderInitializer llama al creadoratapplicationContext () del subclase para obtener el método WebApplicationContext, y continúa encontrando el llamado del método de registroContextLoaderListener (servletcontextcontextcontext). Como resultado, se encuentra que es el OnStartup (servletContext ServletContext) en esta clase. La clase AbstractContextLoaderInitializer se publica a continuación.
Public Abstract Class AbstractContextLoaderInitializer implementa WebApplicationInitializer { / ** Logger disponible para subclases* / Protected final log logger = logFactory.getLog (getClass ()); @Override public void onStartUp (servletContext ServletContext) lanza ServletException {RegisterContextLoLoCeListener (servletContext); } /*** Registre un {@link contextloaderListener} con el contexto de servlet dado. El * {@code contextLoLoGerListener} se inicializa con el contexto de la aplicación devuelto * desde el método de plantilla {@link #CreateroOtApplicationContext ()}. * @param ServletContext El contexto de servlet para registrar el oyente contra */ protegido void registreContextLoLoGerListener (servletContext ServletContext) {WebApplicationContext RootAppContext = CreaterOtApplicationContext (); if (rootAppContext! = NULL) {contextLoLoCerListener oyente = new contextLoLoCListener (rootAppContext); oyente.setContextinitializers (GetRootApplicationContextInitializers ()); servletContext.addListener (oyente); } else {logger.debug ("no contextloaderListener registrado, como" + "createrootapplicationContext () no devolvió un contexto de aplicación"); }} /** * Crea el contexto de la aplicación "<strong> root </strong>" que se proporcionará al * {@code contextLoLoGListener}. * <p> El contexto devuelto se delega a * {@link contextLoLoListener#contextLoLoCLoListener (WebApplicationContext)} y * se establecerá como el contexto principal para cualquier {@code disipterservlet} Aplicación * contexts. As such, it typically contains middle-tier services, data sources, etc. * @return the root application context, or {@code null} if a root context is not * desired * @see org.springframework.web.servlet.support.AbstractDispatcherServletInitializer */ protected abstract WebApplicationContext createRootApplicationContext(); /** * Especifique los inicializadores de contexto de la aplicación que se aplicarán al contexto de la aplicación raíz * con el que se está creando {@code contextloaderListener}. * @since 4.2 * @see #createroOtApplicationContext () * @see contextLoLoGerListener #setContextinitializers */ Proplicated ApplicationContextInitializer <?> [] getrootapplicationContextinitializers () {return null; }}Tenga en cuenta que omitimos la clase abstracta abstractorServletinitializer (consulte el diagrama UML). Esta clase configura principalmente DispatcherServlet, que es la implementación de Spring MVC y otras funciones.
Entonces, ¿quién cargará el abstractContextLoaderInitializer? WebApplicationInitializer ya es una interfaz, y no habrá una clase abstracta para llamarla. Así que intenté buscar en la interfaz WebApplicationInitializer. Debido a que grandes proyectos como Spring están definitivamente orientados a la interfaz, la llamada generalmente se escribe en la interfaz. Luego encontramos la clase SpringServletContainerInitializer, que implementa la interfaz ServletContainerInitializer. Esta clase probablemente significa iniciar todos los aplicaciones web. Se puede decir que esta clase está muy cerca de nuestro objetivo. A continuación se muestra el SpringservletContainerInitializer
@Handlestypes (WebApplicationInitializer.class) public class SpringServeTletContainerInitializer ServletContainerInitializer {@Override public void onStartup (set <class <?>> WebAppinitializerClasses, ServletContext ServletContex LinkedList <WebApplicationInitializer> (); if (WebAppinitializerClasses! = NULL) {for (class <?> waiclass: webAppInitializerClasses) {// Be defensivo: algunos contenedores de servlet nos proporcionan clases no válidas, // no importa lo que diga @handlestypes ... if (! waiclass.isinterface () & ed. WebApplicationInitializer.class.isassignableFrom (waiclass)) {try {inicializers.add ((webapplicationInitializer) waiclass.newinstance ()); } Catch (Throwable EX) {Throw New ServLetException ("no pudo instanciar la clase de Aplicación WebAntializer", ex); }}}}} if (inicializers.isEmpty ()) {servletContext.log ("no se detectaron los tipos de aplicaciones web de primavera en classpath"); devolver; } servletContext.log (inicializadores.size () + "Spring WebApplicationInitializadores detectados en classpath"); AnnotationAwareRoRordComparator.sort (inicializadores); para (WebApplicationInitializer inicializador: inicializadores) {inicializer.onstartup (servletContext); }}}En el último foreach, comience todos los aplicaciones webinitializadores. Entonces, la pregunta es, ¿quién comenzará SpringServletContainerInitializer? La primavera definitivamente no podrá iniciarlo solo.
En el entorno web, solo hay contenedores web. Podemos hacer un punto de interrupción en uno de los lugares anteriores y luego depurarlo (de hecho, podemos depurar completamente = = a lo largo del proceso, lo cual es preciso y rápido, pero esto carece del significado de búsqueda, y el paisaje a lo largo del camino es bastante bueno)
Puede ver el método StartInternal de la clase StandardContext en el paquete org.apache.catalina.core. Esto ya está en el alcance de Tomcat, por lo que se ha logrado nuestro objetivo. Tenga en cuenta que la interfaz ServletContainerInitializer no está debajo del paquete de resorte, sino que es javax.servlet
Supongo que Tomcat usa la interfaz ServletContainerInitializer de Javax.servlet para encontrar las clases que implementan esta interfaz en el contenedor, luego llame a su OnStartup, y luego el SpringServletContainInitializer de Spring Spring puede iniciar todos los IapplacationalInsers, lo que contiene el WebInitializer que escribimos nosotros mismos. Además, Spring Security también está configurado con anotación para implementar WebApplicationInitializer, por lo que Spring es muy extensible. Veamos el código fuente de Tomcat en los próximos días para comprender el mecanismo Tomcat.
Lo anterior es todo el contenido de este artículo. Espero que sea útil para el aprendizaje de todos y espero que todos apoyen más a Wulin.com.