Dans la classe Java, un grand homme du nom de Rod Johnson a constaté que le développement initial de Java Enterprise était dans un état chaotique.
Il a donc décidé d'écrire une infrastructure générale qui pourrait résoudre des problèmes.
Parce qu'il croit fermement que la programmation orientée vers l'interface peut minimiser les changements, mais également faciliter l'expansion et le changement. Il a donc écrit l'interface suivante.
La première chose à créer dans un état chaotique est la mère de tous les objets, le beanfactory, et avec lui, vous pouvez obtenir tous les objets et les attribuer en nourrissant, c'est-à-dire, tout d'abord, Gaia - la mère de la Terre.
Avec le Mother Beanfactory d'origine, pensa Johnson, que se passe-t-il si je voulais obtenir un ensemble d'objets de haricots au lieu d'un ou plusieurs? De plus, que se passe-t-il si l'enfant de la mère veut également donner naissance à un partenaire? Par conséquent, Johnson a créé ListableBeanFactory pour faire fonctionner un ensemble d'objets Bean. Par exemple, GetBeansOfType peut obtenir un ensemble de haricots du même type en fonction de celui-ci; Créé HiérarchicalBeanFactory pour résoudre les problèmes hiérarchiques de plusieurs haricots, tels que GetParentBeanFactory peut obtenir l'usine parentale du Beanfactory.
Ce beanfactory est finalement utilisé sur une application, de sorte que le beanfactory doit avoir la possibilité de se déplacer dans une application. Dans les haricots, il vous suffit de considérer les comportements liés aux haricots, tels que comment obtenir des haricots, le type de haricots, etc.; Et si vous souhaitez leur donner des capacités dans l'application, vous devez en considérer davantage, comme le nom de l'application, le temps de démarrage, l'identifiant, etc. Les comportements et les attributs liés à l'application elle-même, alors Johnson a pensé à créer un applicationContext. Johnson pensait que cette applicationContext devait être en mesure de faire beaucoup de choses, et elle doit être capable de gérer les informations de texte paramétrées et internationalisées, donc elle ajoute l'interface MessageSource; Il doit être en mesure de publier des événements pour découpler les composants, il a donc l'interface ApplicationEventPublisher; Il doit être en mesure d'obtenir des fichiers de ressources, il a donc l'interface ResourcePatterNResolver; Il doit être capable d'avoir différents objets de traitement dans différents environnements, il a donc l'interface permanente.
ApplicationContext hérite de toutes ces interfaces.
Mais la chose la plus importante est que BeanFactory et ApplicationContext doivent avoir des capacités configurables, il existe donc des sous-interfaces ConfigurableBeanFactory et ConfigurableApplicationContext; De plus, le Web était une tendance très importante à l'époque, et c'était un peu unique par rapport aux autres applications, il devait donc obtenir ServletContext, il y avait donc WebApplicationContext.
Jusqu'à présent, Johnson a été abstrait en pensant au comportement de l'interface et ne les a pas mis en œuvre en détail.
En regardant le Beanfactory et ApplicationContext créés, Johnson s'est rendu compte que le travail du jour était loin d'être terminé car il n'y avait pas de véritable solution à la façon de faire fonctionner l'ensemble du système, alors Johnson a commencé à réfléchir à la façon de les implémenter.
La première chose à laquelle Johoson pense est quelles capacités cette implémentation devrait-elle avoir? Bien sûr, nous devons inclure le AutowireCapableBeanFactory, ListableBeanFactory et ConfigurableBeanFactory mentionné précédemment. Par conséquent, la configurableListableBeanFactory a été créée. Deuxièmement, plusieurs capacités pour les objets de haricot doivent être prises en compte, l'une est la capacité d'alias; Le second est la capacité de sauver des objets Singleton; Le troisième est la capacité de cache; Ils sont implémentés dans la classe SimplaLeasRegistry, la classe de défaut de relevance en par défaut et la classe FactoryBeanRegistrySupport respectivement.
Enfin, DefaultListableBeanFactory a été créé, qui est le prototype de toutes les usines IOC au printemps et le premier véritable enfant de Beanfactory. Cet enfant est très important et est devenu la base de la création indépendante de conteneurs du CIO. S'il est étendu et utilisé, la plupart d'entre eux sont hérités ou utilisés en combinaison.
Si vous souhaitez initialiser un DefaultListableBeanFactory, vous pouvez utiliser le code suivant
CLASSPATHRESORCE RES = NOUVEAU CLASSPATHRESORCE ("ApplicationContext.xml"); DefaultListableBeAnfactory f = new defaultListableBeAnfactory (); XmlBeAndeFinitionReader r = new XMLBeAnDefinitionReader (F); R.LoadbeAndefinitions (RES); Ensuite, Johnson pensait que BeanFactory a une implémentation par défaut relativement complète, alors qu'en est-il de l'application Context? JOHNSON a donc créé sans relâche trois implémentations importantes ApplicationContext: FileSystemXmlApplicationContext, ClassPathxmlApplicationContext, AnnotationConfigWebApplicationContex
La première chose que Johnson considère est de savoir comment faire le processus de démarrage de Spring. Il doit être placé dans un niveau relativement abstrait afin que toutes les classes de niveau inférieur puissent être réutilisées. Il a donc implémenté le configurableApplicationContext à l'aide d'un AbstractApplicationContext. Il existe également une fonction très importante, c'est-à-dire le chargement d'un fichier sous la forme d'une ressource, ce qui nécessite de résumer la ressource dans une classe de ressources et de résumer l'implémentation spécifique de la ressource de positionnement vers le ResourceLoader. AbstractApplicationContext doit également hériter du DefaultreSourceLoader pour fournir cette fonction. AbstractApplicationContext a terminé l'ensemble du processus de démarrage (Dieu l'a organisé pour être terminé le lendemain), mais il n'a pas géré Beanfactory. Ainsi, sa sous-classe AbstractreFreshableApplicationContext le fait spécifiquement, l'implémentation de Refreshbeanfactory, CloseBeanFactory, GetBeanFactory gère spécifiquement le cycle de vie du beanfactory, mais abstractrefreshableApplicationConted ne charge toujours pas tous les haricots configurés. Où charger les ressources configurées, il va en fait à la sous-classe inférieure pour le faire, comme FileSystemXmlApplicationContext, qui est de lire un XML ApplicationContext au système de fichiers; ClassPathxMlApplicationContext doit lire ce ClassContex sur le chemin de chargement de classe. AnnotationConfigWebApplicationContext charge les beans à partir de l'annotation du fichier de classe, et la numérisation à ressort commence à partir de maintenant.
Voyant que le cadre principal avait été établi, Johnson s'est endormi avec satisfaction à l'égard d'un sourire.
Le premier jour, Johnson a terminé un cadre global de printemps.
Le deuxième jour, Johnson se préparait à faire face aux problèmes précédents. Par exemple, le processus d'initialisation du conteneur du ressort. Comme le montre la figure, Johnson divise ce processus en de nombreux sous-processus, qui travaillent tous autour du grand objectif de charger des haricots.
Ce processus est placé dans la méthode de rafraîchissement dans l'AbstractApplicationContext. Le code est le suivant: Johnson divise le processus de rafraîchissement en de nombreux sous-processus, et ces sous-processus sont au même niveau abstrait. Cette façon d'écrire consiste à donner aux générations futures un modèle de rôle.
public void Refresh () lève BeanSexception, illégalStateException {synchronisé (this.startupShutdownMonitor) {// Préparez ce contexte à rafraîchissant. preparereFresh (); // Dites à la sous-classe de rafraîchir l'usine de haricots internes. ConfigurableListableBeAnfactory Beanfactory = GetTrAreshBeanFactory (); // Préparez l'usine de bean pour une utilisation dans ce contexte. PréparetBeanFactory (BeanFactory); Essayez {// permet le post-traitement de l'usine de bean dans les sous-classes de contexte. PostprocessBeanFactory (Beanfactory); // Invoquez des processeurs d'usine enregistrés sous forme de haricots dans le contexte. InvokeBeanFactoryPostProcessors (Beanfactory); // Enregistrer les processeurs de haricots qui interceptent la création de haricots. RegisterBeanPostProcessors (BeanFactory); // Initialiser la source de message pour ce contexte. initMessagesource (); // Initialisez l'événement multicasif pour ce contexte. initApplicationEventMulticaster (); // Initialisez d'autres haricots spéciaux dans des sous-classes de contexte spécifiques. onRefresh (); // Vérifiez les haricots de l'écoute et enregistrez-les. registreListeners (); // Instancier tous les singletons restants (non-paresseux). FinishBeanFactoryInitialisation (Beanfactory); // Dernière étape: publier l'événement correspondant. fini finalRefresh (); } Catch (BeanSexception ex) {// Détruiser déjà des singletons pour éviter les ressources pendantes. Destroybeans (); // Réinitialiser le drapeau «actif». CancelRefresh (ex); // propager l'exception à l'appelant. jeter ex; }}} Si vous le regardez à un niveau supérieur, ces processus tournent en fait autour de plusieurs aspects: 1. Rafraîchir le cycle de vie; 2. Initialisation et préparation du haricot; 3. Générer et enregistrer BeanDefinition; 4. Post-processeur de haricot; 5. Définir les messages, les événements et les auditeurs.
1. Cycle de vie rafraîchissant
PreparereFresh, ce processus enregistre principalement le journal et indique que le printemps a commencé, initialise les ressources immobilières (telles que l'initialisation de certaines ressources dans Serlvet) et la vérification des ressources immobilières (telles que l'écriture de clé sans valeur).
OnRefresh, le but est de fournir des contextes d'application spéciaux, afin qu'ils puissent se développer pendant le processus de rafraîchissement. La majeure partie de l'utilisation actuelle est de définir le thème du contexte de l'application du servlet
FinationRefresh, effectuez des travaux de finition, tels que l'initialisation de LifeCycleProcessor, l'événement de publication se terminant pour actualiser, etc.
Cancefresh, modifie principalement l'état actuel en non actif lorsqu'une exception se produit.
2. Initialisation et préparation de haricots
Johnson pense que nous devrions laisser le haricot charger et enregistrer le haricot de manière transparente lorsqu'il est initialisé, donc mon encapsulation est très réussie pour le monde extérieur, donc cette étape fait en fait beaucoup de choses. La figure suivante omet de nombreuses étapes et répertorie uniquement les points clés.
AbstractApplicationContext appellera RefreshbeanFactory. Il vérifiera et fermera d'abord le Beanfactory existant, puis créera un nouveau BeanFactory, puis utilisera cette usine pour charger toutes les définitions BeanDefinitions.
Parmi eux, les effectifs de chargement seront remis aux sous-classes pour différentes implémentations. Par exemple, AbstractXmlApplicationContext est principalement lus via XML; L'implémentation annotationConfigWebApplicationContext appellera le scanner pour scanner les beans de la classe.
3. Générer et enregistrer la définition de la haricot
Après l'analyse de la configuration XML, la méthode PARSEDEFAULTELlement de la defaultBeAndeFinitionDocumentReader effectuera un traitement correspondant basé sur les éléments du XML. Parmi eux, lorsqu'ils rencontrent un élément de haricot, la méthode de la fin de la définition dans le BeanDefinitionReaderUtils sera finalement appelée. Le paramètre réalisé dans cette méthode est BeanDefinitionRegistry, qui rappelle en fait la méthode RegisterBeAnDefinition de DefaultListableBeanFactory pour enregistrer BeanDefinition (DefaultListableBeAnfactory implémente BeanDefinitionRegistry).
4. Post-processeur Beanfactory
Le post-processeur Beanfactory est un moyen fourni par le printemps pour permettre à ses sous-classes d'être flexibles. Il y a 2 étapes au printemps: PostProcessBeanfactory, InvokeBeanFactoryPostProcessors. RegisterBeanPostProcessors instancie et appelez tous lesPostProcessors de BeanPost, qui sont utilisés pour agrandir le haricot avant et après l'initialisation du haricot.
5. Configurer des messages, des événements et des auditeurs
Définissez la source de message par défaut sur DelegatingMessageSource. S'il y a déjà un messages en usine, utilisez ce messages. L'événement Multicaster est simplifasque-éventail. S'il y a déjà une applicationEventMulticaster dans l'usine, utilisez cette applicationEventMulticaster et enregistrez tous les auditeurs d'application pour recevoir des événements.
MessageSource est une méthode importante pour les fichiers de ressources internationales. Spring prend en charge les sources de messages dans ApplicationContext.
Spring fournit l'implémentation par défaut de messagesource, en utilisant java.util.resourcebundle pour extraire des messages. Spring peut accéder directement au message à partir d'applicationContext.getMessage () en configurant un bean avec un ID spécial en tant que MessageSource et en définissant le nom de fichier de i18n. Si dans JSP, vous pouvez également accéder au message via la balise Spring: Message.
Événement: Les événements sont un mécanisme de découplage relativement important. Spring l'a introduit dans le Core ApplicationContext. Son principe est relativement simple. D'une part, le générateur d'événements peut envoyer des événements; D'un autre côté, il semble que l'auditeur d'événements puisse répondre aux événements. L'implémentation spécifique contient essentiellement une collection d'événements d'événements dans le générateur et "enregistre" (c'est-à-dire, join) tous les auditeurs de cette collection d'événements d'événements.
Dans le printemps, ApplicationContext est utilisé comme générateur d'événements, ApplicationListeners est utilisé comme collection d'écoute, et ApplicationEventMulticaster est utilisé pour publier des événements.
Plusieurs étapes pour publier un événement:
Abonnement: Initialement AddApplicationListener à la collection d'écoute.
Publish: ApplicationContext hérite de l'applicationEventPublisher, implémentant ainsi PublisheVent. Cette méthode traversera d'abord la collection ApplicationListeners de cette applicationContext, appellera OnApplicationEvent pour chaque écouteur, de sorte que chaque écouteur sera informé; Une fois cette étape terminée, le même événement sera publié pour tous les éléments d'application du parent ApplicationContext.
L'édition d'événements est très courante. Non seulement nos propres applications peuvent utiliser cette publication d'événements, mais le Spring Framework lui-même utilise également l'édition d'événements. Voici quelques applications d'événements au printemps:
Le ContextrefreshEdEvent sera publié dans FinalRefresh pour indiquer que le rafraîchissement se termine et avertit l'auditeur. Dans l'applicationContext, les méthodes de démarrage et d'arrêt publieront des événements qui indiquent le début du contexte ou la fin.
Après que Johnson ait créé le cadre principal et le processus d'exploitation du printemps, il a constaté que le printemps fournit de nombreux lieux d'extension flexibles. Johnson se prépare donc à annoncer cette utilisation flexible d'expansion le troisième jour.
1. BeanPostprocessor. BeanPostProcessor fournit une interface d'extension une fois la création de bean terminée. Lorsque vous devez effectuer un certain traitement sur les haricots après leur création, BeanPostProcessor est la méthode préférée.
2. Conscient. Le haricot injecté doit connaître certaines parties de son récipient. Spring complète les rappels par le biais de conscience, comme BeanNameAware, qui permet au Bean de connaître son nom. BeanfactoryAware peut permettre au bean de comprendre Beanfactory, ApplicationContextAware, qui permet au bean de fonctionner ApplicationContext. De cette façon, le haricot injecté avec le printemps peut faire un plus large éventail de choses.
Pour l'extension de BeanPostProcessor, Spring lui-même a un exemple de la façon d'identifier un haricot conscient. Les haricots conscients sont des haricots relativement spéciaux et le ressort nécessite des attributs supplémentaires. Alors, comment le ressort sera-t-il utilisé pour le processus d'injection? En fait, Spring ne l'écrit pas dans le processus de traitement de base, mais le place dans l'applicationContextAwareProcessor, le BeanPostProcessor, et enfin invokeawareInterfaces pour déterminer le type de bean et d'injecter les attributs correspondants. Cette approche utilise BeanPostProcessor pour effectuer une autre utilisation étendue, ce qui est vraiment superbe.
private void invokeawareInterfaces (object bean) {if (bean instanceof down) {if (bean instanceof EnvironmentAware) {((EnvironmentAware) Bean) .SetEnvironment (this.ApplicationContext.geTenvironment ()); } if (instance beanof embeddedValueresolVeraware) {((EmbeddedValueresolVeraware) Bean) .SetEledDedValueResolver (New EmbedDedValueResolver (this.ApplicationContext.getBeanFactory ())); } if (bean instanceof ResourceLoAderAware) {((ResourceLoaderAware) Bean) .setResourceLoader (this.ApplicationContext); } if (bean instanceof applicationEventPublisheraware) {((applicationEventPublisheRaWare) bean) .setApplicationEventPublisher (this.applicationContext); } if (bean instanceof MessageSourCeaware) {((messagesourceware) bean) .SetMessagesource (this.ApplicationContext); } if (bean instanceof applicationContextAware) {((applicationContextAware) bean) .setApplicationContext (this.ApplicationContext); }}}Il y a plus de règles pour utiliser le savoir. Par exemple, le code suivant peut percevoir l'applicationContext. Après que le printemps crée ce haricot, il injectera l'applicationContext, afin que nous puissions utiliser ce contexte pour terminer la publication d'événements.
classe publique Hellobean implémente ApplicationContextAware {private applicationContext applicationContext; String privé Helloword = "Hello! World!"; public void setApplicationContext (ApplicationContext Context) {this.ApplicationContext = context; } public void Sethelloword (String Helloword) {this.helloword = helloword; } public String gethelloword () {applicationContext.publisheVent (new PropertyGetTtedEvent ("[" + helloword + "] est Gotted")); Retour Helloword; }} 3. BeanfactoryPostProcessor, ce post-processeur est généralement utilisé pour gérer l'interface étendue créée par Beanfactory. Un exemple est le suivant. Après avoir injecté ce haricot, il imprimera automatiquement le nombre de haricots injectés après la création de haricots:
Classe publique BeanCounter implémente BeanfactoryPostProcessor {@Override public void PostProcessBeanFactory (configurableLlistableBeanfactory Beanfactory) lance Beansexception {System.out.println (beanfactory.getBeanDeFinitionCount ()); }} 4. Factorybean. FactoryBean est un haricot spécial, qui permet l'injection dans les conteneurs de ressort et la génération de vrais haricots, il peut donc être défini de cette manière. FactoryBean lui-même est un haricot, qui a la capacité de fournir des haricots. Ce qui suit commence par l'appel FactoryBean et explique comment Spring utilise ce haricot.
Pour distinguer les haricots ordinaires et les usines, le printemps doit également avoir un processus de jugement et de les manipuler spécialement. Ce processus se trouve dans le GetObjectForBeanInstance de AbstractBeanFactory
objet protégé getObjectForBeanInstance (objet beanInstance, nom de chaîne, nom de haricot string, rootBeAndefinition mbd) {// ne laissez pas le code d'appel essayer de déréférence l'usine si le bean n'est pas une usine. if (beanfactoryutils.isfactorydereference (name) &&! (instance beanInstanceof factorybean)) {lancez new beanisnotafactoryException (transformEdBeanName (name), beanInstance.getClass ()); } // Nous avons maintenant l'instance de haricot, qui peut être un haricot normal ou un casse-usine. // S'il s'agit d'un FactoryBean, nous l'utilisons pour créer une instance de bean, à moins que l'appelant ne souhaite réellement une référence à l'usine. if (! (Instance BeanInstance of FactoryBean) || beanfactoryutils.isfactorydereference (name)) {return beanInstance; } Objet objet = null; if (mbd == null) {object = getCachedObjectForfactoryBean (beanname); } if (object == null) {// return bean instance from Factory. FactoryBean <?> Factory = (FactoryBean <?>) BeanInstance; // Cache objet obtenu de FactoryBean s'il s'agit d'un singleton. if (mbd == null && contientBeAndeFinition (beanname)) {mbd = getMergedLocalBeAnDefinition (beanname); } boolean synthetic = (mbd! = null && mbd.issynthetic ()); object = getObjectFromFactoryBean (Factory, beanname ,! synthétique); } return objet; } On peut voir que s'il s'agit d'un haricot ordinaire, il sera retourné directement, et s'il s'agit d'un Factorybean, l'appel final appellera factory.getObject pour renvoyer l'objet spécifique. Si vous considérez le printemps entier comme une usine abstraite et lors de la production de haricots abstraits, FactoryBean est une usine spécifique qui produit les objets dont vous avez besoin.
Il y a de nombreuses utilisations de FactoryBean au printemps. Pour donner un exemple relativement courant, lors de l'intégration de la SessionFactory de Hibernate, LocalSessionFactoryBean est généralement injecté, mais cette SessionFactory n'est en fait pas un haricot ordinaire. Il peut être produit simplement en l'injectant dans le fichier de configuration. Il a de nombreuses pièces personnalisées, donc le printemps fait de ce bean un Factorybean et contrôle son objet de production.