Prototipo de Spring IOC
El núcleo básico y el punto de partida del marco de resorte son, sin duda, el COI. Como la tecnología central proporcionada por los contenedores de primavera, el COI completó con éxito la inversión de dependencias: desde la gestión activa de la clase principal de las dependencias hasta el control global de las dependencias por contenedores de primavera.
¿Cuáles son los beneficios de hacer esto?
Por supuesto, es el llamado "desacoplamiento", lo que puede hacer que la relación entre los módulos del programa sea más independiente. Spring solo necesita controlar las dependencias entre estos módulos y crear, administrar y mantener estos módulos en función de estas dependencias durante el inicio del contenedor y el proceso de inicialización. Si necesita cambiar las dependencias entre módulos, ni siquiera necesita cambiar el código del programa. Solo necesita modificar las dependencias cambiadas. Spring restablecerá estas nuevas dependencias en el proceso de inicio e inicialización del contenedor nuevamente. En este proceso, es necesario tener en cuenta que el código en sí no necesita reflejar la declaración de la situación de dependencia específica del módulo, pero solo necesita definir la interfaz del módulo requerido. Por lo tanto, esta es una idea típica orientada a la interfaz. Al mismo tiempo, es mejor expresar las dependencias en forma de archivos de configuración o anotaciones. Las clases de procesamiento de Spring relevantes ensamblarán módulos basados en estos archivos de configuración externos, o escanearán la anotación para llamar al procesador de anotación interna para ensamblar módulos para completar el proceso del COI.
El propósito del COI es una inyección de dependencia llamada Di. A través de la tecnología del COI, el contenedor Ultimate nos ayudará a completar la inyección de dependencia entre los módulos.
Además, el punto final es que en el proceso de Spring IOC, siempre debemos ser claros sobre la línea principal anterior. No importa cuán compleja sea la sintaxis en tiempo real y la estructura de clase, su función y propósito son los mismos: es completar el "ensamblaje" del módulo confiando en el archivo de configuración descrito como el "dibujo" de ensamblaje. La sintaxis compleja es solo un medio para lograr este propósito.
El llamado prototipo del COI, para mostrar el diagrama esquemático del COI más simple, también podríamos hacer un prototipo completamente simple para ilustrar este proceso:
Primero, hay varios módulos que definimos, incluido el módulo principal y el módulo de dependencia definido por las dos interfaces:
clase MainModule {private dependmodulea modulea; privado dependeModuleB módulob; Public dependmodulea getModulea () {return Modulea; } public void setmodulea (dependmodulea modulea) {this.modulea = modulea; } public DependModuleB getModuleB () {return ModuleB; } public void setModuleB (dependModuleB móduloB) {this.moduleB = móduloB; }} interfaz dependermodulea {public void FuncFrmoduleA ();} interfaz dependerModuleB {public void FuncFROmmmoduleB ();} La clase dependeModuleaImpl implementa dependermodulea {@Override public void FuncFrOmmodulea () {System.Println ("Esto es FUNC de Module a"); }} class dependModuleBImpl implements dependModuleB {@Override public void FuncFrmoduleB () {System.out.println ("Esto es func de Módulo B"); }}Si no adoptamos el COI, pero confiamos en el módulo principal en sí para controlar la creación de su módulo dependiente, entonces será así:
public class SimpleioCdemo {public static void main (string [] args) lanza ClassNotFoundException {mainModule mainModule = new MainModule (); MainModule.SetModulea (nuevo dependsModuleaImpl ()); MainModule.SetModuleB (nuevo dependsModuleBImpl ()); MainModule.getModulea (). FuncFRommodulea (); mainModule.getModuleB (). FuncFROmmOB (); }}Esta es nuestra definición simplificada de prototipo de contenedor IOC. Cuando el contenedor se inicializa después del inicio, leerá el archivo de configuración escrito por el usuario. Aquí tomamos el archivo de configuración de propiedades simples como ejemplo. Solo cuando el usuario llama al método GetBean, el bean correspondiente se ensamblará y cargará realmente de acuerdo con el archivo de configuración. Un mapa utilizado para guardar el frijol ensamblado se mantiene dentro del prototipo del contenedor que definimos. Si hay un frijol que cumple con los requisitos, no es necesario que se cree nuevamente:
clase SimpleiCoContainer {Propiedades privadas Properties = New Properties (); Mapa privado <String, Object> ModulEmap = new Hashmap <> (); {try {Properties.load (new FileInputStream (nuevo archivo ("simplióc.properties"))); } catch (Exception e) {E.PrintStackTrace (); }} Public Object GetBean (String ModuleName) lanza ClassNotFoundException {Object instanceObj; if (moduleMap.get (moduleName)! = null) {system.out.println ("return Old Bean"); return ModulEmap.get (ModuleName); } System.out.println ("Crear nuevo frijol"); Cadena fullClassName = Properties.getProperty (moduleName); if (fullClassName == NULL) tire nuevo ClassNotFoundException (); else {clase <? extiende objeto> clazz = class.forname (fullClassName); intente {instanceObj = clazz.newinstance (); instanceObj = buildAtTachedModules (Modulename, instanceObj); ModulEmap.put (ModuleName, instanceObj); return instanceObj; } catch (InstanciationException e) {E.PrintStackTrace (); } catch (ilegalAccessException e) {E.PrintStackTrace (); }} return null; } objeto privado BuiltAtTachedModules (String ModuleName, Object OnstoneObj) {Set <String> PropertiesKeys = Properties.StringPropertynames (); Campo [] campos = instanciaBJ.getClass (). GetDeclaredFields (); For (clave de cadena: PropertiesKeys) {if (key.contains (moduleName) &&! key.equals (moduleName)) {try {class <? extiende objeto> clazz = class.forname (Properties.getProperty (Properties.getProperty (Key))); for (campo campo: campos) {if (field.gettype (). isassignableFrom (clazz)) field.set (instanceObj, clazz.newinstance ()); }} catch (Exception e) {E.PrintStackTrace (); }}} return instanceObj; }}Este es el archivo de configuración de dependencia que escribimos utilizando el archivo de configuración de propiedades. Este archivo de configuración es el "dibujo" de nuestro módulo de ensamblaje. La sintaxis aquí está completamente definida por nosotros. En el contenedor Real Spring IOC, para expresar una lógica de dependencia más compleja, se utilizará un archivo de configuración de formato XML más desarrollado o una configuración de anotación más nueva, y el procesador de anotaciones se utilizará para completar el análisis del dibujo:
mainModule = com.rocking.demo.mainmodulemainmodule.modulea = modulAlainModule.moduleB = moduleBModuleA = com.rowing.demo.dependmoduleAimplModuleB = com.rowing.demo.DependModuleBImpl
Este es el código de prueba. Se puede ver que podemos obtener completamente módulos que cumplan con los requisitos a través del contenedor IOC que definimos. Al mismo tiempo, también podemos encontrar que el contenedor que definimos puede mantener estos frijoles para nosotros. Cuando se ha ensamblado y creado un frijol, no es necesario que se cree nuevamente.
public class Simpleiocdemo {public static void main (string [] args) lanza ClassNotFoundException {SimpleiCoContainer Container = new SimpleiCoTontainer (); DependerModulea modulea = (dependerModulea) contenedor.getBean ("modulea"); Modulea.funcfrommodulea (); DependerModuleB MODULEB = (dependModuleB) contenedor.getBean ("módulob"); MODULEB.FUNCFROMMOB (); MainModule MainModule = (MainModule) Container.getBean ("MainModule"); MainModule.getModulea (). FuncFRommodulea (); mainModule.getModuleB (). FuncFROmmOB (); Container.getBean ("MainModule"); }}Este es el prototipo de contenedor IOC que creé en función de la idea básica del COI. Aunque Spring IOC tiene una sintaxis compleja, las tareas completadas al final son las mismas en el núcleo, los llamados "todos los cambios no se separarán de su esencia".
Proceso específico de Spring IOC
La última vez, se mostró el prototipo de la implementación general del COI. Entonces, ¿cómo implementar específicamente el proceso de carga de POJOS en el marco de resorte de este contenedor basado en la configuración de la información de metadatos? Hay muchos lugares en todo el proceso de trabajo de contenedores del COI Spring que están diseñados para ser bastante flexibles, proporcionando a los usuarios mucho espacio para completar sus propias tareas, en lugar de completar el proceso mecánico del contenedor.
Este es el diagrama de proceso de todo el proceso de trabajo del contenedor del COI:
1. Etapa de inicio del contenedor (1) Carga de información del archivo de configuración (2) Análisis de la información del archivo de configuración (3) Asamblea Beandefinition
(4) Primero del procesamiento, la metainformación, como los archivos de configuración o las anotaciones y la información de la clase de Javabean, se cargan en el contenedor IOC. El contenedor lee un archivo de configuración de formato XML. Este archivo de configuración es una dependencia declarada por el usuario y el ensamblaje que necesita atención especial. Es un "dibujo externo" temprano para ensamblar el frijol. El motor de análisis en el contenedor puede analizar la metainformación de los caracteres en el formulario de texto que escribimos en una Definición de Bean que se puede reconocer dentro del contenedor, que puede comprender el BeanDefinition. Se convierte en una estructura de clase similar al mecanismo de reflexión. Estadefinición de Bean obtenida mediante el análisis de Javabeans y los archivos de configuración obtiene la estructura básica de ensamblar un Javabean que cumple con los requisitos. Si necesita modificar el beandefinition además de la beandefinition, se realiza este postprocesamiento. El postprocesamiento generalmente se procesa a través del beanFactoryPostProcessor en el marco de resorte.
Todavía usamos los ejemplos que utilizamos la última vez para ilustrar el principio de funcionamiento de esta Definición de Bean: hay tres frijoles, el módulo principal MainModule y los módulos de dependencia dependen de Modulea y dependenmoduleB. El primero depende de los dos últimos módulos. En el archivo de configuración, generalmente declaramos dependencias como esta:
<? 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 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id = "mainmodule"> <name de propiedad = "modulea"> <ref beanea " <Property Name = "ModuleB"> <ref Bean = "ModuleB"/> </property> </ Bean> <Bean Id = "Modulea"> </ Bean> <Bean ID = "ModuleB"> </ Bean> </Beans>
Este es nuestro programa que demuestra el ensamblaje de un contenedor estándar de BeanFactory (una de las implementaciones de los contenedores de Spring IOC) al archivo de configuración anterior:
clase MainModule {private dependmodulea modulea; privado dependeModuleB módulob; Public dependmodulea getModulea () {return Modulea; } public void setmodulea (dependmodulea modulea) {this.modulea = modulea; } public DependModuleB getModuleB () {return ModuleB; } public void setModuleB (dependModuleB móduloB) {this.moduleB = móduloB; }} interfaz dependermodulea {public void FuncFrmoduleA ();} interfaz dependerModuleB {public void FuncFROmmmoduleB ();} La clase dependeModuleaImpl implementa dependermodulea {@Override public void FuncFrOmmodulea () {System.Println ("Esto es FUNC de Module a"); }} class dependModuleBImpl implements dependModuleB {@Override public void FuncFrmoduleB () {System.out.println ("Esto es func de Módulo B"); }} public class simplyOcDemo {public static void main (string [] args) lanza ClassNotFoundException {defaultListableFactory beanFactory = new DefaultListableBeanFactory (); XMLBeanDefinitionReader Reader = new XMLBeanDefinitionReader (BeanFactory); lector.loadBeanDefinitions ("Beans.xml"); MainModule MainModule = (MainModule) BeanFactory.getBean ("MainModule"); MainModule.getModulea (). FuncFRommodulea (); mainModule.getModuleB (). FuncFROmmOB (); }}Aquí nuestro archivo de configuración y Javabean están cargados y leídos y analizados. Aquí el proceso de generación y uso de Beandefinition está oculto en él. Este es el proceso general que realmente ocurre dentro del COI:
public class SimpleioCdemo {public static void main (string [] args) lanza ClassNotFoundException {defaultListableBeanFactory beanFactory = new DefaultListableBeanFactory (); AbstractBeanDefinition MainModule = new RootBeanDefinition (MainModule.Class); AbstractBeanDefinition Modulea = new rootBeanDefinition (dependModuleaImpl.class); AbstractBeanDefinition ModuleB = new RootBeanDefinition (dependmodulebimpl.class); BeanFactory.RegisterBeanDefinition ("MainModule", MainModule); BeanFactory.RegisterBeanDefinition ("Modulea", Modulea); BeanFactory.RegisterBeanDefinition ("ModuleB", ModuleB); MutablePropertyValues PropertyValues = new MutablePropertyValues (); PropertyValues.Add ("Modulea", Modulea); PropertyValues.Add ("ModuleB", ModuleB); MainModule.SetPropertyValues (PropertyValues); MainModule Module = (MainModule) BeanFactory.getBean ("MainModule"); MODULE.GETMODULEA (). FUNCFROMMOLEA (); MODULE.GETMODULEB (). FUNCFROMMOB (); }}Después de cargar y leer la meta información del XML, el motor de análisis del IOC creará el módulo mencionado en una beandefinition en función de su tipo real. Esta Definición de Bean puede considerarse como un proceso de reflexión o proxy. El propósito es hacer que el contenedor IOC borre la estructura de frijoles del objeto de instancia que se creará en el futuro, y luego registre estas estructuras de frijoles en la factura de beanFactory, y luego agregue las dependencias del módulo principal al módulo principal del módulo principal en forma de inyección setter (esto depende de si el método de setter o el método de inicialización proporcionado por el módulo principal. Después de eso, solo llame al método GetBean para producir los frijoles que cumplan con los requisitos. Esta es la siguiente etapa del proceso, y hablaremos de ello más tarde.
Después de registrar la información sobre el "dibujo" de Beandefinition en BeanFactory, aún podemos hacer cambios en la Definición Bean de Bean. Este es uno de los aspectos flexibles del diseño de primavera para los usuarios mencionados anteriormente. No significa que todos los procesos sean incontrolables, pero deja mucho espacio para que los usuarios jueguen en muchos lugares. El método específico es utilizar el procesador BeanFactory BeanFactoryPostPossor para intervenir en el procesamiento de BeanFactory para reescribir aún más la parte de beandefinition que necesitamos modificar. Este proceso corresponde al proceso de "postprocesamiento" en el proceso.
Tomando uno de los procesadores comunes: el procesador de configuración del marcador de posición del atributo como ejemplo, es procesar la Factory de beans registrada después de que se haya construido, de modo que los contenidos en el atributo de BeanDefinition correspondiente se modifiquen a la información en el archivo de configuración especificado del procesador de configuración:
DefaultListableBeanFactory BeanFactory = new DefaultableBeanFactory (); xmlBeanDefinitionReader lector = new XMLBeanDefinitionReader (BeanFactory); Reader.LoadBeanDefinitions (New ClassPathResource ("Beans.xml")); PropertyPoureRurer, Configurator = New PropertyPoldPlaceConfonfonfonfonfonfonfonfonfonfoner ();) ClasspathResource ("About.properties")); configure.postProcessBeanFactory (beanFactory);BeanFactoryPostProcessor procesará la Factory Bean. El resultado es cambiar algunos atributos definidos en BeanDefinition a alguna información en la ubicación del BeanFactoryPostProcessor.
2. Etapa de instanciación de frijoles
Bajo la guía de los "dibujos internos" procesados de Beandefinition, el contenedor puede transformar aún más la parte del beandefifinición en un objeto de instancia activado existente en la memoria a través de la reflexión o la producción de byecodo dinámico CGLIB, y luego ensamblar el objeto de dependencia especificado por BeanDefinition en el objeto de instancia recién creado a través de inyección de setter o inyección de inicialización. Aquí, la referencia del objeto de dependencia en realidad se asigna a los atributos del objeto que deben depender.
Pero debe tenerse en cuenta aquí que la instancia creada no es solo una instancia simple de definición de frijoles, sino una instancia de beanwrapper envuelta por Spring. ¿Por qué debe usarse para envolver el frijol en el método de beanwrapper? Porque BeanWrapper proporciona una interfaz para acceder a las propiedades de frijoles de manera uniforme. Después de crear el marco básico de frijoles, se deben establecer las propiedades en él. El método de establecimiento de cada frijol es diferente, por lo que será muy complicado si lo configura directamente con reflexión. Por lo tanto, Spring proporciona este envoltorio para simplificar la configuración de la propiedad:
BeanWrapper beanWrapper = new BeanWrapperImpl(Class.forName("com.rocking.demo.MainModule"));beanWrapper.setPropertyValue( "moduleA", Class.forName("com.rocking.demo.DepModuleAImpl").newInstance());beanWrapper.setPropertyValue( "moduleB", Class.forname ("com.rowing.demo.depModuleBImpl"). NewInStance ()); MainModule MainModule = (MainModule) BeanWrapper.GetWrappedInstance (); MainModule.getModulea (). Funcfroma (); MainModule.getModuleB (). Funcfromb ();El proceso anterior muestra que en primavera, puede comprender la estructura del frijol de instancia que está envuelto en el futuro al obtener el contenedor reflexivo de la clase y hacer el embalaje. Use el método de configuración de propiedades unificados setPropertyValue para establecer propiedades para la instancia de este paquete. La instancia final de Bean obtenida se obtiene a través de GetWrappingInstance, y puede encontrar que sus atributos han sido asignados con éxito.
En este momento, la instancia de Bean en realidad es completamente utilizable, pero Spring también preparó estrategias flexibles para nosotros en la etapa de instanciación para completar la intervención del usuario en esta etapa. Similar a la definición de beandefinition de BeanFactoryPostPossor Control en la etapa de inicio del contenedor, durante la etapa de instanciación, Spring proporciona un procesador BeanPostProcessor para operar en las instancias ensambladas para completar posibles cambios:
Aquí hay un ejemplo para ilustrar que define una clase de implementación del procesador de beanpost, implementando los métodos después del proceso de autorinicialización y posprocessbeforinitialización para definir las operaciones realizadas por separado después y antes del ensamblaje de la instancia de Bean. Después de que BeanFactory agrega este procesador, cada vez que se ensambla el método GetBean, los dos métodos se llamarán en la instancia de Bean ensamblada de acuerdo con el "dibujo" (incluida la instancia dependiente creada durante el proceso de ensamblaje). Estos métodos pueden modificar estas instancias de frijoles.
Aquí hay un ejemplo como este (MainModule y sus dependencias son las mismas que anteriormente en este artículo):
clase Modulec {cadena privada x; public String getx () {return x; } public void setX (String x) {this.x = x; }} class ModulePostProcessor implementa BeanPostProcessor {@Override Public Object PostProcessAfterInitialization (objeto de objeto, cadena String) lanza Beansexception {system.out.println (string); if (objeto instanceof modulec) {System.out.println (string); ((Modulec) objeto) .setx ("después"); } objeto de retorno; } @Override Public Object PostProcessBeForeInitialization (Object Object, String String) lanza Beansexception {if (Object OnstoneOf Modulec) {((Modulec) Object) .setx ("antes"); } objeto de retorno; }} Clase pública MuySimpleiOckernal {public static void main (string [] args) lanza ClassNotFoundException, BeanSexception, InstanciationException, IlegalAccessException {DefaultListableBeanFactory BeanFactory = new DefaultListableBeanFactory (); XMLBeanDefinitionReader Reader = new XMLBeanDefinitionReader (BeanFactory); lector.loadBeanDefinitions (nuevo classpathResource ("beans.xml")); ModulePostProcessor PostProcessor = new ModulePostProcessor (); BeanFactory.addBeanPostProcessor (postprocesador); MainModule Module = (MainModule) BeanFactory.getBean ("MainModule"); Modulec Modulec = (Modulec) BeanFactory.getBean ("Modulec"); System.out.println (modulec.getx ()); }}Este es el archivo de configuración de dependencia para el bean:
<? 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 http://www.springframework.org/schema/beans http://www.springfframework.org/schema/beans/sspring-beanss.xsd"> <" <propiedad name = "modulea"> <ref bean = "Modulea"/> </propiety> <Property Name = "ModuleB"> <ref Bean = "ModuleB"/> </Property> </Bean> <Bean Id = "Modulea"> <Property Name = "Infoa"> <Valor> $ {Modulea.infoa} </value> </spersi name = "Infob"> <value> Información de ModuleB </value> </property> </bean> <bean id = "modulec"> </bean> </beans>Desde el resultado final, podemos ver que cada vez que la instancia de GetBean (incluida la generada por dependencias) obtenga llamando al método GetBean será recuperada por el Procesador BeanPost para el procesamiento previo y posterior.
Además del procesamiento de frijoles ensamblados similares al procesador de beanpost anterior, Spring también puede establecer funciones de devolución de llamada para el proceso de inicialización y destrucción de los frijoles al configurar el método init y destruir método. Estas funciones de devolución de llamada también pueden proporcionar de manera flexible la oportunidad de cambiar las instancias de frijoles.
Todo el proceso del COI de primavera es en realidad esencialmente el mismo que el prototipo del COI que escribimos nosotros mismos, excepto que el diseño complejo permite que el proceso del COI proporcione a los usuarios un espacio de manera más flexible y efectiva. Además, el COI de Spring también ha logrado un diseño exquisito en términos de seguridad, estabilidad del contenedor y eficiencia de conversión de metadatos a frijoles, lo que hace que la base del COI, un recipiente de resorte sea estable.