Bienvenido al Tutorial de Ejemplo de Spring IoC. El Framework de Spring está construido sobre el principio de Inversión de Control. La inyección de dependencias es la técnica para implementar IoC en las aplicaciones.
Spring IoC
Hoy echaremos un vistazo al Contenedor de Spring IoC. También repasaremos el Bean de Spring. A continuación se presenta la tabla de contenidos para una navegación rápida a las diferentes secciones del tutorial de Spring IoC.
- Spring IoC
- Spring Bean
- Ámbitos del Bean de Spring
- Configuración del Bean de Spring
- Ejemplo de Spring IoC y Spring Bean
Contenedor de inversión de control de Spring
Spring IoC es el mecanismo para lograr el desacoplamiento entre las dependencias de los objetos. Para lograr el desacoplamiento y la vinculación dinámica de los objetos en tiempo de ejecución, las dependencias de los objetos son inyectadas por otros objetos ensambladores. El contenedor Spring IoC es el programa que inyecta las dependencias en un objeto y lo prepara para nuestro uso. Ya hemos visto cómo podemos utilizar la Inyección de Dependencias de Spring para implementar IoC en nuestras aplicaciones. Las clases del contenedor Spring IoC son parte de los paquetes org.springframework.beans
y org.springframework.context
. El contenedor Spring IoC nos proporciona diferentes formas de desacoplar las dependencias de los objetos. BeanFactory
es la interfaz raíz del contenedor Spring IoC. ApplicationContext
es la interfaz secundaria de la interfaz BeanFactory
que proporciona características de Spring AOP, i18n, etc. Algunas de las interfaces secundarias útiles de ApplicationContext
son ConfigurableApplicationContext
y WebApplicationContext
. El Framework Spring proporciona una serie de clases de implementación de ApplicationContext útiles que podemos utilizar para obtener el contexto de Spring y luego el Bean de Spring. Algunas de las implementaciones útiles de ApplicationContext que usamos son;
- AnnotationConfigApplicationContext: Si estamos utilizando Spring en aplicaciones Java independientes y utilizando anotaciones para la configuración, entonces podemos utilizar esto para inicializar el contenedor y obtener los objetos bean.
- ClassPathXmlApplicationContext: Si tenemos un archivo de configuración xml para beans de Spring en una aplicación independiente, podemos utilizar esta clase para cargar el archivo y obtener el objeto del contenedor.
- FileSystemXmlApplicationContext: Esto es similar a ClassPathXmlApplicationContext, excepto que el archivo de configuración xml se puede cargar desde cualquier lugar en el sistema de archivos.
- AnnotationConfigWebApplicationContext y XmlWebApplicationContext para aplicaciones web.
Por lo general, si estás trabajando en una aplicación Spring MVC y tu aplicación está configurada para usar el Framework Spring, el contenedor de inversión de control (IoC) de Spring se inicializa cuando la aplicación comienza y, cuando se solicita un bean, las dependencias se inyectan automáticamente. Sin embargo, para una aplicación independiente, es necesario inicializar el contenedor en algún lugar de la aplicación y luego usarlo para obtener los beans de Spring.
Bean de Spring
Un Bean de Spring no es algo especial, cualquier objeto en el framework de Spring que inicializamos a través del contenedor de Spring se llama Bean de Spring. Cualquier clase normal de Java POJO puede ser un Bean de Spring si está configurada para inicializarse a través del contenedor mediante la provisión de información de metadatos de configuración.
Ámbitos de los Beans de Spring
Hay cinco ámbitos definidos para los Spring Beans.
- singleton: solo se creará una instancia del bean para cada contenedor. Este es el ámbito predeterminado para los spring beans. Al usar este ámbito, asegúrese de que el bean no tenga variables de instancia compartidas, de lo contrario, podría provocar problemas de inconsistencia de datos.
- prototype: se creará una nueva instancia cada vez que se solicite el bean.
- request: es igual que el ámbito prototype, sin embargo, está destinado a ser utilizado para aplicaciones web. Se creará una nueva instancia del bean para cada solicitud HTTP.
- session: se creará un nuevo bean para cada sesión HTTP por el contenedor.
- global-session: se utiliza para crear beans de sesión global para aplicaciones de portlets.
El Framework de Spring es extensible y también podemos crear nuestros propios ámbitos. Sin embargo, la mayoría de las veces estamos bien con los ámbitos proporcionados por el framework.
Configuración de Spring Bean
El Framework de Spring proporciona tres formas de configurar beans para ser utilizados en la aplicación.
- Configuración Basada en Anotaciones – Al utilizar las anotaciones @Service o @Component. Los detalles del alcance pueden ser proporcionados con la anotación @Scope.
- Configuración Basada en XML – Mediante la creación de un archivo XML de configuración de Spring para configurar los beans. Si estás utilizando el framework Spring MVC, la configuración basada en XML puede ser cargada automáticamente escribiendo un poco de código de plantilla en el archivo web.xml.
- Configuración Basada en Java – A partir de Spring 3.0, podemos configurar los beans de Spring utilizando programas Java. Algunas anotaciones importantes utilizadas para la configuración basada en Java son @Configuration, @ComponentScan y @Bean.
Ejemplo de Proyecto de Spring IoC y Spring Bean
Veamos los diferentes aspectos del contenedor Spring IoC y las configuraciones de los Beans de Spring con un proyecto Spring simple. Para mi ejemplo, estoy creando un proyecto Spring MVC en Spring Tool Suite. Si eres nuevo en Spring Tool Suite y Spring MVC, por favor lee el Tutorial de Spring MVC con Spring Tool Suite. La estructura final del proyecto se ve como en la imagen a continuación. Veamos los diferentes componentes del proyecto Spring IoC y Spring Bean uno por uno.
Configuración de Spring Bean basada en XML
MyBean es una clase Java POJO simple.
package com.journaldev.spring.beans;
public class MyBean {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Archivo de configuración XML de Spring
Código de servlet-context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="https://www.springframework.org/schema/mvc"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="https://www.springframework.org/schema/beans"
xmlns:context="https://www.springframework.org/schema/context"
xsi:schemaLocation="https://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<context:component-scan base-package="com.journaldev.spring" />
<beans:bean name="myBean" class="com.journaldev.spring.beans.MyBean" scope="singleton" ></beans:bean>
</beans:beans>
Observa que MyBean está configurado usando el elemento bean
con el ámbito singleton.
Configuración de Spring Bean basada en anotaciones
package com.journaldev.spring.beans;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.web.context.WebApplicationContext;
@Service
@Scope(WebApplicationContext.SCOPE_REQUEST)
public class MyAnnotatedBean {
private int empId;
public int getEmpId() {
return empId;
}
public void setEmpId(int empId) {
this.empId = empId;
}
}
MyAnnotatedBean está configurado usando @Service y el alcance se establece en Request.
Clase del controlador Spring IoC
La clase HomeController manejará las solicitudes HTTP para la página de inicio de la aplicación. Inyectaremos nuestros beans de Spring en esta clase de controlador a través del contenedor WebApplicationContext.
package com.journaldev.spring.controller;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.journaldev.spring.beans.MyAnnotatedBean;
import com.journaldev.spring.beans.MyBean;
@Controller
@Scope("request")
public class HomeController {
private MyBean myBean;
private MyAnnotatedBean myAnnotatedBean;
@Autowired
public void setMyBean(MyBean myBean) {
this.myBean = myBean;
}
@Autowired
public void setMyAnnotatedBean(MyAnnotatedBean obj) {
this.myAnnotatedBean = obj;
}
/**
* Simply selects the home view to render by returning its name.
*/
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
System.out.println("MyBean hashcode="+myBean.hashCode());
System.out.println("MyAnnotatedBean hashcode="+myAnnotatedBean.hashCode());
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
String formattedDate = dateFormat.format(date);
model.addAttribute("serverTime", formattedDate );
return "home";
}
}
Descriptor de implementación
Necesitamos configurar nuestra aplicación para el framework Spring para que se cargue la metadata de configuración y se inicialice el contexto.
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="https://java.sun.com/xml/ns/javaee"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
Casi toda la configuración anterior es código de plantilla generado automáticamente por la herramienta STS.
Ejecutar la aplicación de ejemplo de Bean Spring IoC
Ahora, cuando inicie la aplicación web, se cargará la página de inicio y en la consola se imprimirán los siguientes registros al actualizar la página varias veces.
MyBean hashcode=118267258
MyAnnotatedBean hashcode=1703899856
MyBean hashcode=118267258
MyAnnotatedBean hashcode=1115599742
MyBean hashcode=118267258
MyAnnotatedBean hashcode=516457106
Ten en cuenta que MyBean está configurado para ser un singleton, por lo que el contenedor siempre devuelve la misma instancia y el hashcode siempre es el mismo. De manera similar, para cada solicitud, se crea una nueva instancia de MyAnnotatedBean con un hashcode diferente.
Configuración de Bean de Spring basada en Java
Para aplicaciones independientes, podemos utilizar configuración basada en anotaciones y también basada en XML. El único requisito es inicializar el contexto en algún lugar del programa antes de usarlo.
package com.journaldev.spring.main;
import java.util.Date;
public class MyService {
public void log(String msg){
System.out.println(new Date()+"::"+msg);
}
}
MyService es una clase Java simple con algunos métodos.
package com.journaldev.spring.main;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(value="com.journaldev.spring.main")
public class MyConfiguration {
@Bean
public MyService getService(){
return new MyService();
}
}
La clase de configuración basada en anotaciones que se utilizará para inicializar el contenedor Spring.
package com.journaldev.spring.main;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MyMainClass {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(
MyConfiguration.class);
MyService service = ctx.getBean(MyService.class);
service.log("Hi");
MyService newService = ctx.getBean(MyService.class);
System.out.println("service hashcode="+service.hashCode());
System.out.println("newService hashcode="+newService.hashCode());
ctx.close();
}
}
A simple test program where we are initializing the AnnotationConfigApplicationContext
context and then using getBean()
method to get the instance of MyService. Notice that I am calling getBean method two times and printing the hashcode. Since there is no scope defined for MyService, it should be a singleton and hence hashcode should be the same for both the instances. When we run the above application, we get following console output confirming our understanding.
Sat Dec 28 22:49:18 PST 2013::Hi
service hashcode=678984726
newService hashcode=678984726
Si estás buscando una configuración basada en XML, simplemente crea el archivo de configuración XML de Spring y luego inicializa el contexto con el siguiente fragmento de código.
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"applicationContext.xml");
MyService app = context.getBean(MyService.class);
Eso es todo para el ejemplo de IoC de Spring, ámbitos de Bean de Spring y detalles de configuración. Descarga el proyecto de ejemplo de IoC de Spring y Bean de Spring desde el siguiente enlace y juega con él para entenderlo mejor.
Descargar Proyecto Spring Beans
Referencia: Página de Spring.IO para IoC
Source:
https://www.digitalocean.com/community/tutorials/spring-ioc-bean-example-tutorial