¿Por qué comenzar a mirar el código fuente de Spring?
He estado escribiendo código a la mitad de las carreras durante casi un año y medio. He estado usando el marco de primavera desde que comencé a trabajar. Aunque puedo usarlo y construirlo, a menudo no entiendo los principios detrás de esto, como: cómo la primavera controla las transacciones, cómo SpringMVC maneja las solicitudes y cómo se implementa AOP ... ¡esto hace que las personas se sientan muy incómodas, así que comience a estudiar lentamente el código fuente de la primavera mientras lee el libro!
Cómo ver de manera eficiente el código fuente
Mi respuesta es mirar el código fuente con preguntas específicas, de lo contrario, es muy fácil quedarse atascado en los detalles del código fuente y luego se desmayará. Finalmente, descubres lo que has estado leyendo durante mucho tiempo.
introducción
Spring es un marco de nivel de diseño de código abierto que resuelve el problema de acoplamiento suelto entre la capa lógica de negocios y otras capas, e integra ideas de programación orientadas a la interfaz en toda la aplicación del sistema. También es una de las habilidades esenciales en el trabajo de Java ...
Dado que registra el proceso de análisis del código fuente de primavera, no explicaré el uso detallado.
Código central
<Spendency> <MoupRoupId> org.springframework </groupid> <artifactID> spring-context </arfactid> <versever> 5.0.2.Release </versewer> </dependence>
uso
Aplicación de clase pública {public static void main (string [] args) {beandefinitionregistry beanFactory = new DefaultListableBeanFactory (); XMLBeanDefinitionReader Reader = new XMLBeanDefinitionReader (BeanFactory); ClasspathResource recurso = nuevo classpathResource ("bean.xml"); // El punto de entrada para toda la carga de recursos. lector.loadBeanDefinitions (recurso); }}Descifrado
DefaultListableBeanFactory es la implementación predeterminada del registro de primavera y la carga de frijoles. Se puede llamar el antepasado en toda la plantilla del COI de primavera.
Seguimiento de la factura predeterminada ListableBeanFactory, puede encontrar los siguientes bloques de código. ¿Cuál es el propósito de este diseño?
public abstractAUTOWIRECAPABLEBeanFactory () {super (); IgnoredEpendencyInterface (beannameaware.class); IgnoredEpendencyInterface (beanFactoryaware.class); IgnoredEpendencyInterface (beanClassLoLoaderaware.class);}Por ejemplo, cuando hay el atributo B en A, Spring instanciará automáticamente el atributo B si se encuentra que el atributo B no se instancia al obtener el atributo A. Esta también es una característica importante proporcionada en la primavera. En algunos casos, B no se inicializará, como la implementación de la interfaz Beannameaware.
Spring introduce esto: cuando el ensamblaje automático, ignore la interfaz de dependencia dada, como analizar las dependencias de registro del contexto de la aplicación a través de otros métodos, similar a la inyección de BeanFactory a través de BeanFactoryaware o la inyección de AplicationContext a través de ApplicationContextAware.
Gestión de recursos
La interfaz de recursos se utiliza para administrar archivos, URL, classpath y otros recursos. El recurso es responsable de leer el archivo de configuración, es decir, encapsular el archivo de configuración en un recurso y luego entregarlo al XMLBeanDefinitionReader para su procesamiento.
Analizador XML
XMLBeanDefinitionReader es una implementación de la lectura de archivos de recursos de primavera, análisis y registro, y debemos centrarnos en esta clase.
Track reader.loadBeanDefinitions(resource); , podemos ver el siguiente código central (excluir comentarios y hacer excepciones)
public int loadBeanDefinitions (EncodedResource EncodedResource) arroja beandefinitionstoreException {try {inputStream inputStream = encodedresource.getResource (). getInputStream (); intente {inputSource inputSource = new InputSource (inputStream); if (encodedResource.getEncoding ()! = NULL) {inputSource.SetEncoding (EncodedResource.getEncoding ()); } return doloadbeanDefinitions (inputSource, EncodedResource.getResource ()); } finalmente {inputStream.Close (); }}}El código anterior realizó primero una operación de codificación en recursos, con el propósito de preocuparse por el problema de codificación en XML
Si observa cuidadosamente InputSource inputSource = new InputSource(inputStream); , El nombre de su paquete es en realidad org.xml.sax, por lo que podemos concluir que Spring usa el análisis de saxo y usa InputSource para decidir cómo leer archivos XML.
Finalmente, los datos preparados se pasan a la parte de procesamiento del núcleo real a través de parámetros doLoadBeanDefinitions(inputSource, encodedResource.getResource())
Obtener documento
1 doLoadBeanDefinitions(inputSource, encodedResource.getResource()); , omita varias capturas y comentarios
Int DoloadBeanDefinitions protegido (InputSource InputSource, Resource Resource) arroja beandefinitionStoreException {try {document doc = doloadDocument (inputSource, recurso); RETURN REGISTBEANDEFINITIONS (DOC, RECURSO); }} 2. doLoadDocument(inputSource, resource);
Documento protegido DoloadDocument (InputSource InputSource, Resource Resource) lanza la excepción {return this.documentLoader.loadDocument (inputSource, getEntityResolver (), this.errorHandler, getValidationModeForResource (recursos), isnamespaceAware ();}Primero, puede obtener el modo de verificación (DTD o XSD) del archivo XML a través de GetValidationModeForResource. Puede establecer el método de verificación usted mismo. Por defecto, la validación_auto está habilitada, es decir, el modo de verificación se obtiene automáticamente. Lea el archivo XML a través de InputStream y verifique si contiene palabras DOCTYPE. Si lo contiene, es DTD, de lo contrario devolverá XSD.
Los patrones comunes de verificación de archivos XML son:
clase pública XMLVALIDATIONMODEDETETECTOR { /*** Indica que la validación de DTD debe usarse (encontramos una declaración "DOCTYPE"). */ public static final int validation_dtd = 2; /*** Indica que la validación de XSD debe usarse (no se encuentra la declaración de "doctype"). */ public static final int validation_xsd = 3; public int DetectValidationMode (InputStream InputStream) lanza IOException {}} Un parámetro EntityResolver está involucrado en this.documentLoader.loadDocument
Public Document LoadDocument (InputSource InputSource, EntityResolver EntityResolver, ErrorHandler ErrorHandler, Int ValidationMode, Boolean Namespaceaware) lanza la excepción {}¿Qué es EntityResolver? Explicación oficial: si una aplicación SAX necesita implementar el procesamiento personalizado de entidades externas, debe implementar esta interfaz y registrar una instancia con la unidad SAX utilizando el método SetEntityResolver. Es decir, para analizar un XML, SAX leerá por primera vez la declaración en el documento XML y buscará la definición de DTD correspondiente de acuerdo con la declaración, para verificar el documento, las reglas de búsqueda predeterminadas (es decir, descarga de red, descarga la definición de DTD a través de la dirección DTD URI declarada por XML) y realizar la autenticación. El proceso de descarga es un proceso largo, y cuando la red no está disponible, se informará un error aquí porque no se ha encontrado el DTD correspondiente.
La función de EntityResolver es que el proyecto en sí mismo puede proporcionar un método de cómo encontrar declaraciones de DTD, es decir, el programa implementa el proceso de encontrar DTD, lo que evita encontrar las declaraciones correspondientes a través de la red.
3.EntityResolver acepta dos parámetros:
Public Abstract InputSource ResolveEntity (String PublicID, String SystemID) lanza SaxException, IOException;
3.1 Defina el archivo Bean.xml, con el contenido de la siguiente manera (modo XSD)
<? xml versión = "1.0" encoding = "utf-8"?> <beans xmlns = "http://www.springframework.org/schema/beans" xmlns: xsi = "http://www.w3.org/2001/xmlschema-instance" "" "" xsi: schemalocation = "http://www.springframework.org/schema/beans.xsd"> </beans>
Analizado a los siguientes dos parámetros:
3.2 Defina el archivo Bean.xml, con el contenido de la siguiente manera (modo DTD)
<? xml versión = "1.0" encoding = "utf-8"?> <! Doctype Beans pública "-// Spring // Dtd Bean 2.0 // en" "http://www.springframework.org/dtd/spring-beans.dtd"> <ósss>
Analizado a los siguientes dos parámetros:
3.3 Spring utiliza DelegatingEntityResolver para analizar EntityResolver
Public Class DelegatingEntityResolver {@Override @nullable public inputSource ResolveEntity (String PublicId, @Nullable String SystemId) lanza saxexception, ioexception {if (systemID! = null) {if (systemID.endswith (dtd_suffix)) {devuelve esto.dtresolver.resolveentity (publicid); } else if (systemID.endswith (xsd_suffix)) {return this.schemaresolver.resolveEntity (publicid, systemID); }} return null; }}Podemos ver que se usan diferentes analizadores para diferentes modos
Registrar un frijol
Después de leer la verificación XML de análisis, continúe rastreando el código y vea cómo Spring registra la información de Bean basada en el documento
public class xmlBeanDefinitionReader {public int registroBeanDefinitions (documento doc, recursos de recursos) lanza beandefinitionstoreException {// crea documentReader BeanDefinitionDocumentReader DocumentReader = CreateBeanDefinitionDocumentReer (); // Registre el número de beandefinitions antes de las estadísticas int countbefore = getregistry (). GetBeanDefinitionCount (); // registrar beandefinition documentReader.RegisterBeanDefinitions (DOC, CreateReaderContext (Resource)); // Registre el número de beandefinitions cargadas esta vez return getregistry (). GetBeanDefinitionCount () - CountBore; }}Al registrar un Bean, primero use una clase BeandefinitionParserDelegate para determinar si es el espacio de nombres predeterminado. La implementación es determinar si el URI del espacio de nombres es igual al URI predeterminado:
clase pública beandefinitionParserDelegate {public static final String beans_namespace_uri = "http://www.springframework.org/schema/beans"; Public boolean isDefaultNamespace (@@nullable String Namespaceuri) {return (! StringUtils.hasLength (Namespaceuri) || beans_namespace_uri.equals (namespaceuri)); }} Track documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); , donde DOC se convierte a través de LoadDocument en el bloque de código anterior. El objetivo principal de este método es extraer nodos raíz (frijoles)
clase pública DefaultBeanDefinitionDocumentReader {@Override public void RegistroBeanDefinitions (documento Doc, XMLReaderContext ReaderContext) {this.readerContext = readercontext; logger.debug ("Cargando definiciones de frijoles"); Elemento root = doc.getDocumentElement (); DoregisterBeanDefinitions (raíz); }} Rastrear doRegisterBeanDefinitions(root) y veremos el siguiente flujo de procesamiento
protegido void doregisterBeanDefinitions (Element Root) {// ... String ProfileSpec = root.getAttribute (perfil_attribute); // ... // Implementación vacía Preprocessxml (raíz); parsebeandefinitions (root, this.delegate); // Implementación vacía postprocessxml (raíz); this.delegate = parent;}Primero, analice el perfil (la forma más común de jugar es que los objetos de Bean inicializados por diferentes perfiles son diferentes, por lo que implementan múltiples entornos)
El siguiente análisis utiliza el modo de método de plantilla, donde preprocessXML y PostProcessXML son métodos vacíos, de modo que las subclases posteriores pueden realizar algún procesamiento antes y después del análisis. Solo anula estos dos métodos.
Analizar y registrar beandefinition, esta parte del código es relativamente simple
Clase pública DefaultBeanDefinitionDocumentReader { / *** Resuelve otros nodos bajo la importación del nodo raíz "," alias "," bean ".* @param nombre de nodo raíz* / protegido void parseBeanDefinitions (element root, beandefinitionParserDelegate delegate) {if (delegate.isdefaultamespace (root))) root.getChildNodes (); Delegate.ParSecustomElement (ELE); importeBeanDefinitionResource (ELE); (delegate.nodenameEquals (ele, nested_beans_element)) {// recurse doregisterBeanDefinitions (ELE); bdholder = Delegate.ParseBeanDefinitionElement (ELE); getReaderContext (). GetRegistry ()); BeanComponentDefinition (bdholder)); Delegar el método ParseBeanDefinitionElement de la clase BeanDefinitionParserDelegate para el análisis de elementos y devuelve la instancia del tipo de beDefinitionLeTer Type BDHoder (incluidos los diversos atributos de la clase de archivo de configuración, nombre, ID, alias, etc.)
Cuando el titular bd no está vacío, si hay un atributo personalizado en el nodo infantil de la etiqueta predeterminada, la etiqueta personalizada se analiza y se analiza nuevamente, y luego BeanDefinitionReaderUtils.registerBeanDefinition(); Registra al BDholder y envía el evento de registro, informando al frijol de escucha relevante que el registro ha tenido éxito.
Resumir
Después de unos pocos otoño, invierno, primavera y verano desconocidos, todo seguirá la dirección que desee ...
De acuerdo, lo anterior es todo el contenido de este artículo. Espero que el contenido de este artículo tenga cierto valor de referencia para el estudio o el trabajo de todos. Si tiene alguna pregunta, puede dejar un mensaje para comunicarse. Gracias por su apoyo a Wulin.com.
Di algo
Código de texto completo: https://gitee.com/battcn/battcn-spring-source/tree/master/chapter1 (descarga local)