Container Overview

Container Overview

La interfaz org.springframework.context.ApplicationContext representa el contenedor IoC de Spring y es responsable de instanciar, configurar y ensamblar los beans. El contenedor obtiene las instrucciones sobre qué componentes instanciar, configurar y ensamblar al leer metadatos de configuración. Estos metadatos pueden representarse como clases anotadas con component, clases de configuración con métodos factory, o archivos XML externos o scripts Groovy. Con cualquiera de estos formatos, se puede componer la aplicación y las complejas interdependencias entre sus componentes.

Varias implementaciones de la interfaz ApplicationContext forman parte del núcleo de Spring. En aplicaciones independientes (stand-alone), es común crear una instancia de AnnotationConfigApplicationContext o ClassPathXmlApplicationContext.

En la mayoría de los escenarios de aplicación, no se requiere código explícito para instanciar uno o más contenedores IoC de Spring. Por ejemplo:

El siguiente diagrama muestra una vista general de cómo funciona Spring. Las clases de la aplicación se combinan con metadatos de configuración para que, tras crear e inicializar el ApplicationContext, se tenga un sistema completamente configurado y ejecutable.

image.png

Como muestra el diagrama, el contenedor IoC de Spring consume metadatos de configuración, que indican cómo el contenedor debe instanciar, configurar y ensamblar los componentes. El contenedor está totalmente desacoplado del formato en que se escriben estos metadatos. Actualmente, muchos desarrolladores eligen configuración basada en Java:

  • Configuración basada en anotaciones: definir beans usando anotaciones en las clases como component.
  • Configuración basada en Java: definir beans externamente a tus clases Java usando anotaciones como @Configuration@Bean@Import y @DependsOn.

La configuración de Spring consiste en al menos una (y usualmente varias) definiciones de beans gestionadas por el contenedor. En Java, esto se logra con métodos anotados con @Bean dentro de clases @Configuration, donde cada método corresponde a un bean.

Estas definiciones suelen incluir objetos de capa de servicio, persistencia (como repositorios o DAOs), presentación (controladores web) o infraestructura (como EntityManagerFactory de JPA o colas JMS). Generalmente, no se configuran objetos de dominio detallados en el contenedor, ya que eso corresponde a la lógica de negocio o repositorios.

XML as an External Configuration DSL

XML-based configuration metadata configures these beans as <bean/> elements inside a top-level <beans/> element. The following example shows the basic structure of XML-based configuration metadata:

<?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
		https://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="..." class="...">
		<!-- collaborators and configuration for this bean go here -->
	</bean>

	<bean id="..." class="...">
		<!-- collaborators and configuration for this bean go here -->
	</bean>

	<!-- more bean definitions go here -->

</beans>
  • id: Identificador único del bean.
  • class: Clase completa del bean (fully qualified class name)

El valor del atributo id puede utilizarse para hacer referencia a objetos colaboradores. El XML para hacer referencia a objetos colaboradores no se muestra en este ejemplo. Consulte Dependencies para obtener más información.

Para instanciar un contenedor, es necesario proporcionar la ruta o rutas de acceso a los archivos de recursos XML a un constructor ClassPathXmlApplicationContext que permita al contenedor cargar metadatos de configuración desde diversos recursos externos, como el sistema de archivos local, el CLASSPATH de Java, etc.

ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

ℹ️ Después de aprender sobre el contenedor IoC de Spring, puede que quieras saber más sobre la abstracción de Recursos de Spring (como se describe en Recursos) que proporciona un mecanismo conveniente para leer un InputStream desde ubicaciones definidas en una sintaxis URI. En particular, las rutas de Recursos se utilizan para construir contextos de aplicaciones, como se describe en Application Contexts and Resource Paths

El siguiente ejemplo muestra el archivo de configuración de objetos de la capa de servicios (services.xml):

<?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
		https://www.springframework.org/schema/beans/spring-beans.xsd">

	<!-- services -->

	<bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
		<property name="accountDao" ref="accountDao"/>
		<property name="itemDao" ref="itemDao"/>
		<!-- additional collaborators and configuration for this bean go here -->
	</bean>

	<!-- more bean definitions for services go here -->

</beans>

El siguiente ejemplo muestra el archivo daos.xml con los data access objects:

<?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
		https://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="accountDao"
		class="org.springframework.samples.jpetstore.dao.jpa.JpaAccountDao">
		<!-- additional collaborators and configuration for this bean go here -->
	</bean>

	<bean id="itemDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaItemDao">
		<!-- additional collaborators and configuration for this bean go here -->
	</bean>

	<!-- more bean definitions for data access objects go here -->

</beans>

En el ejemplo anterior, la capa de servicio está formada por la clase PetStoreServiceImpl y dos objetos de acceso a datos de tipos JpaAccountDao y JpaItemDao (basados en el estándar JPA Object-Relational Mapping). El elemento property name hace referencia al nombre de la propiedad JavaBean, y el elemento ref hace referencia al nombre de otra definición bean. Esta vinculación entre los elementos id y ref expresa la dependencia entre objetos colaboradores. Para obtener más información sobre la configuración de las dependencias de un objeto, consulte Dependencias.

Composing XML-based Configuration Metadata

Puede resultar útil que las definiciones de beans abarquen varios archivos XML. A menudo, cada archivo de configuración XML individual representa una capa lógica o módulo en su arquitectura.

Puedes utilizar el constructor ClassPathXmlApplicationContext para cargar beans desde fragmentos XML.

Este constructor toma múltiples localizaciones de Resource, como se mostró en la sección anterior

ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

Alternativamente, utilice una o más apariciones del elemento para cargar definiciones de bean desde otro archivo o archivos. El siguiente ejemplo muestra cómo hacerlo:

<beans>
	<import resource="services.xml"/>
	<import resource="resources/messageSource.xml"/>
	<import resource="/resources/themeSource.xml"/>

	<bean id="bean1" class="..."/>
	<bean id="bean2" class="..."/>
</beans>

En el ejemplo anterior, las definiciones externas de bean se cargan desde tres archivos: services.xml, messageSource.xml y themeSource.xml. Todas las rutas de ubicación son relativas al archivo de definición que realiza la importación, por lo que services.xml debe estar en el mismo directorio o ruta de clase que el archivo que realiza la importación, mientras que messageSource.xml y themeSource.xml deben estar en una ubicación de recursos por debajo de la ubicación del archivo de importación. Como puede ver, se ignora la barra oblicua inicial. Sin embargo, dado que estas rutas son relativas, es mejor no utilizar la barra. El contenido de los archivos que se importan, incluido el elemento de nivel superior, deben ser definiciones de beans XML válidas, de acuerdo con el esquema de Spring.

ℹ️ Es posible, aunque no recomendable, hacer referencia a archivos en directorios padre utilizando una ruta relativa “../”. Al hacerlo, se crea una dependencia de un archivo que está fuera de la aplicación actual. En particular, esta referencia no se recomienda para URLs classpath: URLs (por ejemplo, classpath:../services.xml), donde el proceso de resolución en tiempo de ejecución elige la raíz classpath “más cercana” y luego busca en su directorio padre. Los cambios en la configuración del classpath pueden llevar a la elección de un directorio diferente e incorrecto.

Siempre puedes utilizar localizaciones de recursos completamente cualificadas en lugar de rutas relativas: por ejemplo, file:C:/config/services.xml o classpath:/config/services.xml. Sin embargo, ten en cuenta que estás acoplando la configuración de tu aplicación a ubicaciones absolutas específicas. Generalmente es preferible mantener una indirección para dichas ubicaciones absolutas - por ejemplo, a través de marcadores de posición “${…}” que se resuelven contra las propiedades de la JVM en tiempo de ejecución.

El propio espacio de nombres proporciona la función de import. Hay disponibles más funciones de configuración más allá de las definiciones de beans simples en una selección de espacios de nombres XML proporcionados por Spring - por ejemplo, los espacios de nombres context y util.

Using the Container

ApplicationContext es la interfaz para una factory avanzada capaz de mantener un registro de diferentes beans y sus dependencias. Usando el método T getBean(String name, Class<T> requiredType), puedes recuperar instancias de tus beans.

ApplicationContext te permite leer definiciones de beans y acceder a ellas, como muestra el siguiente ejemplo:

// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

// retrieve configured instance
PetStoreService service = context.getBean("petStore", PetStoreService.class);

// use configured instance
List<String> userList = service.getUsernameList();

La variante más flexible es GenericApplicationContext en combinación con reader delegates—por ejemplo, con XmlBeanDefinitionReader para archivos XML, como muestra el siguiente ejemplo:

GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();

También puede utilizar GroovyBeanDefinitionReader para archivos Groovy, como muestra el siguiente ejemplo:

GenericApplicationContext context = new GenericApplicationContext();
new GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy");
context.refresh();

Puedes combinar y alternar estos reader delegates en el mismo ApplicationContext, leyendo definiciones de beans desde diversas fuentes de configuración.

Luego, puedes usar getBean para recuperar instancias de tus beans. La interfaz ApplicationContext tiene algunos otros métodos para obtener beans, pero, idealmente, el código de tu aplicación no debería usarlos. De hecho, el código de tu aplicación no debería llamar al método getBean() en absoluto y, por lo tanto, no debería depender de las APIs de Spring.

Por ejemplo, la integración de Spring con web frameworks proporciona inyección de dependencias para varios componentes del web framework, como controllers y JSF-managed beans, permitiéndote declarar una dependencia en un bean específico a través de metadatos (como una anotación de autowiring).