Pourquoi commencer à regarder le code source Spring
J'écris du code à mi-chemin par le biais de carrières depuis près d'un an et demi. J'utilise le framework Spring depuis que j'ai commencé à travailler. Bien que je puisse l'utiliser et le construire, je ne comprends souvent pas les principes derrière, tels que: comment Spring contrôle les transactions, comment SpringMVC gère les demandes et comment AOP est implémenté ... Cela rend les gens très mal à l'aise, alors commencez à étudier lentement le code source du printemps en lisant le livre !!!
Comment afficher efficacement le code source
Ma réponse est de regarder le code source avec des questions spécifiques, sinon il est très facile de rester coincé dans les détails du code source, puis vous vous évanouirez. Enfin, vous découvrez ce que vous lisez depuis longtemps.
introduction
Spring est un cadre au niveau de la conception open source qui résout le problème de couplage lâche entre la couche logique métier et d'autres couches, et intègre des idées de programmation orientées vers l'interface tout au long de l'application système. C'est également l'une des compétences essentielles du travail Java ...
Puisqu'il enregistre le processus d'analyse du code source Spring, je ne développerai pas l'utilisation détaillée.
Code de base
<dependency> <proupId> org.springframework </prôdId> <ArtefactId> printemps-context </refactive> <version> 5.0.2.release </-version> </pependance>
usage
public class application {public static void main (String [] args) {beanDefinitionRegistry beanfactory = new defaultListableBeAnfactory (); XMLBeAnDefinitionReader Reader = new XMLBeAndeFinitionReader (BeanFactory); ClassPathResource Resource = new ClassPathResource ("bean.xml"); // Le point d'entrée de l'ensemble du chargement des ressources. Reader.LoadBeAnDefinitions (ressource); }}Décryptage
DefaultListableBeAnfactory est l'implémentation par défaut de l'enregistrement de ressort et du chargement des haricots. Il peut être appelé l'ancêtre de tout le modèle de CIO du printemps.
Suivant le par défaut d'IntendableBeAnfactory, vous pouvez trouver les blocs de code suivants. Quel est le but de cette conception?
public abstractAutowireCapableBeAnfactory () {super (); IgnorePendencyInterface (beanNameAware.class); IgnorePendencyInterface (beanfactoryAware.class); IgnorePendencyInterface (beanclassloadheraware.class);}Par exemple, lorsqu'il y a l'attribut B dans A, Spring Instanciera automatiquement l'attribut B s'il est constaté que l'attribut B n'est pas instancié lors de l'obtention d'attribut A. Il s'agit également d'une fonctionnalité importante fournie au printemps. Dans certains cas, B ne sera pas initialisé, comme la mise en œuvre de l'interface BeanNameAware.
Spring le présente: lors de l'auto-assemblage, ignorez l'interface de dépendance donnée, telle que l'analyse des dépendances d'enregistrement de contexte d'application via d'autres méthodes, similaires à l'injection de Beanfactory via BeanfactoryAware ou l'injection d'application Context via ApplicationContextAware.
Gestion des ressources
L'interface de ressource est utilisée pour gérer le fichier, l'URL, le chemin de classe et d'autres ressources. La ressource est responsable de la lecture du fichier de configuration, c'est-à-dire, encapsulant le fichier de configuration dans une ressource, puis la remettre au traitement XMLBeAndeFinitionReader.
Analyse de xml
XMLBeAnDefinitionReader est une implémentation de la lecture, de l'analyse et de l'enregistrement des fichiers de ressources de Spring, et nous devons nous concentrer sur cette classe.
Track reader.loadBeanDefinitions(resource); , nous pouvons voir le code de base suivant (exclure les commentaires et lancer des exceptions)
public int chargeBeAndeFinitions (EncodedResource EncodedResource) lève BeanDefinitionStoreException {try {inputStream inputStream = EncodeDResource.getResource (). getInputStream (); try {inputSource inputSource = new InputSource (inputStream); if (encodedResource.getEncoding ()! = null) {inputSource.SetEncoding (EncodedResource.getEncoding ()); } return doloAdBeAnDefinitions (InputSource, EncodedResource.getResource ()); } enfin {inputStream.close (); }}}Le code ci-dessus a d'abord effectué une opération de codage sur Resource, dans le but de s'inquiéter du problème de codage dans XML
Si vous observez soigneusement InputSource inputSource = new InputSource(inputStream); , son nom de package est en fait org.xml.sax, nous pouvons donc conclure que Spring utilise l'analyse de saxophone et utilise l'entrée pour décider comment lire les fichiers XML.
Enfin, les données préparées sont transmises à la partie de traitement du noyau réelle à travers des paramètres doLoadBeanDefinitions(inputSource, encodedResource.getResource())
Obtenir un document
1. doLoadBeanDefinitions(inputSource, encodedResource.getResource()); , omettre plusieurs captures et commentaires
Protected int doloadbeAnDefinitions (InputSource InputSource, Resource Resource) lance BeanDeFinIitionStoreException {try {document doc = doloadDocument (InputSource, ressource); RETOUR REGISTREBEADEDEFINITIONS (DOC, RESSOURCE); }} 2. doLoadDocument(inputSource, resource);
Document protégé DOLOADDOCUMENT (InputSource InputSource, Resource Resource) lève Exception {return this.DocumentLoader.LoadDocument (InputSource, GetentityResolver (), This.ErrorHandler, GetValidationModeForResource (Resource)Tout d'abord, vous pouvez obtenir le mode de vérification (DTD ou XSD) du fichier XML via getValidationModeForResource. Vous pouvez définir la méthode de vérification vous-même. Par défaut, Validation_Auto est activé, c'est-à-dire que le mode de vérification est automatiquement obtenu. Lisez le fichier XML via InputStream et vérifiez s'il contient des mots doctype. S'il le contient, c'est DTD, sinon il renverra XSD.
Les modèles de vérification de fichiers XML communs sont:
La classe publique XMLValidationModeDetector {/ ** * indique que la validation DTD doit être utilisée (nous avons trouvé une déclaration "doctype"). * / public static final int validation_dtd = 2; / ** * Indique que la validation XSD doit être utilisée (aucune déclaration "doctype"). * / public static final int validation_xsd = 3; public int DetectValidationMode (InputStream InputStream) lève IOException {}} Un paramètre EntityResolver est impliqué dans this.documentLoader.loadDocument méthode.DocumentLoader.LoadDocument
Document public LoadDocument (InputSource InputSource, EntityResolver EntityResolver, errorhandler errorhandler, int validationmode, boolean namespaceaware) lève l'exception {}Qu'est-ce que EntityResolver? Explication officielle: Si une application SAX doit implémenter le traitement personnalisé des entités externes, elle doit implémenter cette interface et enregistrer une instance avec le lecteur SAX à l'aide de la méthode SetEntityResolver. C'est-à-dire que pour analyser un XML, sax lirera d'abord la déclaration sur le document XML et recherchera la définition DTD correspondante en fonction de la déclaration, afin de vérifier le document, les règles de recherche par défaut (c'est-à-dire le téléchargement du réseau, télécharger la définition DTD via l'adresse DTD URI déclarée par XML) et effectuer l'authentification. Le processus de téléchargement est un long processus, et lorsque le réseau n'est pas disponible, une erreur sera signalée ici car le DTD correspondant n'a pas été trouvé.
La fonction d'EntityResolver est que le projet lui-même peut fournir une méthode pour trouver des déclarations DTD, c'est-à-dire que le programme met en œuvre le processus de recherche DTDS, ce qui évite de trouver des déclarations correspondantes via le réseau.
3.EntityResolver accepte deux paramètres:
Public Abstract EntingSource Resolveentity (String publicId, String Systemid) lève saxException, ioException;
3.1 Définissez le fichier bean.xml, avec le contenu comme suit (mode XSD)
<? xml version = "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>
Analysé aux deux paramètres suivants:
3.2 Définissez le fichier bean.xml, avec le contenu comme suit (mode DTD)
<? xml version = "1.0" Encoding = "UTF-8"?> <! Doctype Beans public "- // printemps // dtd bean 2.0 // en" "http://www.springframework.org/dtd/spring-beans.dtd"> <ebys> </ Beans>
Analysé aux deux paramètres suivants:
3.3 Spring utilise la déléguation de Rupture pour analyser EntityResolver
classe publique DelegatingEntityResolver {@Override @nullable public entrée Resolveentity (String publicId, @Nullable String Systemid) lève saxException, ioException {if (SystemId! = Null) {if (Systemid.endswith (dtd_suffix)) {return this.dtdresolver.resololveentity (publicId); } else if (systemid.endswith (xsd_suffix)) {return this.schemaresolver.resolveentity (publicId, systemid); }} return null; }}Nous pouvons voir que différents analyseurs sont utilisés pour différents modes
Enregistrer un haricot
Après avoir lu l'analyse de vérification XML, continuez à suivre le code et voyez comment Spring enregistre les informations Bean en fonction du document
classe publique xmlBeAnDefinitionReader {public int regrinsBeAndefinitions (document doc, ressource ressource) lève beanDefinitionStoreException {// create documentReader beanDefinitionDocumentReader DocumentReader = CreateBeAnDefinitionDocumentReader (); // Enregistrez le nombre de BeanDefinitions avant les statistiques int countFore = getRegistry (). GetBeAnDefinitionCount (); // Enregistrer BeanDefinition DocumentReader.RegisterBeAnDefinitions (Doc, CreateRenerContext (ressource)); // Enregistrez le nombre de BeanDefinitions chargées cette fois return getRegistry (). GetBeAnDefinitionCount () - countfore; }}Lors de l'enregistrement d'un bean, utilisez d'abord une classe BeanDefinitionParserDelegate pour déterminer s'il s'agit de l'espace de noms par défaut. L'implémentation consiste à déterminer si l'espace de noms URI est égal à l'URI par défaut:
classe publique 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)); , où DOC est converti via LoadDocument dans le bloc de code précédent. Le but principal de cette méthode est d'extraire les nœuds racinaires (haricots)
classe publique defaultBeAndeFinitionDocumentReader {@Override public void registerBeAndefinitions (document doc, xmlreaderContext ReaderContext) {this.readerContext = ReaderContext; Logger.debug ("Chargement des définitions de bean"); Élément root = doc.getDocumentElement (); DoregisterBeAnDefinitions (racine); }} Suivre doRegisterBeanDefinitions(root) et nous verrons le flux de traitement suivant
Protected void doregisterBeAndefinitions (élément root) {// ... string proFilEpec = root.getAttribute (profil_attribute); // ... // Implémentation vide PreprocessXml (root); ParseBeAndefinitions (Root, this.delegate); // Implémentation vide PostProcessXML (root); this.delegate = parent;}Premièrement, analyser le profil (la façon la plus courante de jouer est que les objets de bean initialisés par différents profils sont différents, ils implémentent donc plusieurs environnements)
L'analyse suivante utilise le mode de méthode du modèle, où PreprocessXML et PostProcessXML sont tous deux des méthodes vides, de sorte que les sous-classes suivantes peuvent effectuer un traitement avant et après l'analyse. Il suffit de remplacer ces deux méthodes.
Analyser et enregistrer BeanDefinition, cette partie du code est relativement simple
Classe publique DefaultBeAnDefinitionDocumentReader {/ ** * Résoudre les autres nœuds sous l'importation du nœud racine "," alias "," bean ". * @param Nom du nœud racine * / Protected void parsebeAndefinitions (élément root, beandefinitionParserDelegate Delegate) {if (Delegate.isdefaultNamespace (root)) {nodeList Nl = Delegate root.getChildNodes (); pour (int i = 0; i <nl.getLength (); Delegate.ParseCustriel (ele);}}}} else {Delegate.PaSECust else if (Delegate.NodeNameEquals (ele, alias_element)) {ProcessaliasRegistration (ele); Les étiquettes de fèves (Ele);}} / ** * Processus de traitement (Ele ont ensuite été enregistrées dans le registre. {bdHolder = Delegate.DecorateBeAnDeFinitionIfrequequired (ele, bdholder); Enregistrez la définition du bean avec le nom '"+ bdHolder.getBeAnName () +"' ", ele, ex);} // Envoi de l'événement d'enregistrement. GetReaderContex Déléguer la méthode ParseBeAnDefinitionElement de la classe BeanDefinitionParserDelegate pour l'analyse des éléments, et renvoyez l'instance de BEANDEFINITIONSHER TYPE BDHOLDER (y compris les différents attributs de la classe de fichiers de configuration, nom, ID, alias, etc.)
Lorsque le titulaire de BD retourné n'est pas vide, s'il y a un attribut personnalisé dans le nœud enfant de l'étiquette par défaut, l'étiquette personnalisée est analysée et analysée à nouveau, puis BeanDefinitionReaderUtils.registerBeanDefinition(); enregistre le titulaire de BD et envoie l'événement d'inscription, informant le haricot d'écoute pertinent que l'enregistrement a réussi.
Résumer
Après quelques personnes, hiver, printemps et été inconnus, tout suivra la direction que vous voulez ...
D'accord, ce qui précède est l'intégralité du contenu de cet article. J'espère que le contenu de cet article a une certaine valeur de référence pour l'étude ou le travail de chacun. Si vous avez des questions, vous pouvez laisser un message pour communiquer. Merci pour votre soutien à wulin.com.
Dire quelque chose
Code texte complet: https://gitee.com/battcn/battcn-spring-source/tree/master/chapter1 (téléchargement local)