Exemple de IoC Spring, Spring Bean Tutorial

Bienvenue dans le Tutoriel d’Exemple de IoC de Printemps. Le Framework Spring est construit sur le principe d’Inversion de Contrôle. L’injection de dépendance est la technique pour implémenter IoC dans les applications.

IoC de Spring

Aujourd’hui, nous allons examiner le Conteneur IoC de Spring. Nous passerons également en revue le Bean Spring. Ci-dessous se trouve la table des matières pour une navigation rapide vers différentes sections du tutoriel IoC de Spring.

  1. IoC de Spring
  2. Bean Spring
  3. Portées de Bean Spring
  4. Configuration de Bean Spring
  5. Exemple de IoC de Spring et Bean Spring
    1. Configuration de Bean Spring basée sur XML
    2. Configuration de Bean Spring basée sur Annotations
    3. Configuration de Bean Spring basée sur Java

Conteneur Spring IoC

Le conteneur Spring IoC est le mécanisme permettant d’obtenir un couplage lâche entre les dépendances des objets. Afin d’atteindre un couplage lâche et une liaison dynamique des objets à l’exécution, les dépendances des objets sont injectées par d’autres objets assembleurs. Le conteneur Spring IoC est le programme qui injecte les dépendances dans un objet et le rend prêt à être utilisé. Nous avons déjà examiné comment nous pouvons utiliser l’injection de dépendance Spring pour mettre en œuvre IoC dans nos applications. Les classes du conteneur Spring IoC font partie des packages org.springframework.beans et org.springframework.context. Le conteneur Spring IoC nous offre différentes façons de découpler les dépendances des objets. BeanFactory est l’interface principale du conteneur Spring IoC. ApplicationContext est l’interface enfant de l’interface BeanFactory qui fournit des fonctionnalités Spring AOP, i18n, etc. Certaines des interfaces filles utiles de ApplicationContext sont ConfigurableApplicationContext et WebApplicationContext. Le Framework Spring propose plusieurs classes d’implémentation utiles de ApplicationContext que nous pouvons utiliser pour obtenir le contexte Spring, puis le Bean Spring. Certaines des implémentations utiles de ApplicationContext que nous utilisons sont;

  • AnnotationConfigApplicationContext: Si nous utilisons Spring dans des applications Java autonomes et utilisons des annotations pour la configuration, alors nous pouvons utiliser ceci pour initialiser le conteneur et obtenir les objets Bean.
  • ClassPathXmlApplicationContext : Si nous avons un fichier de configuration xml pour les beans Spring dans une application autonome, alors nous pouvons utiliser cette classe pour charger le fichier et obtenir l’objet conteneur.
  • FileSystemXmlApplicationContext : C’est similaire à ClassPathXmlApplicationContext, sauf que le fichier de configuration xml peut être chargé de n’importe où dans le système de fichiers.
  • AnnotationConfigWebApplicationContext et XmlWebApplicationContext pour les applications web.

Généralement, si vous travaillez sur une application Spring MVC et que votre application est configurée pour utiliser le framework Spring, le conteneur IoC Spring s’initialise au démarrage de l’application et lorsque l’on demande un bean, les dépendances sont injectées automatiquement. Cependant, pour une application autonome, vous devez initialiser le conteneur quelque part dans l’application, puis l’utiliser pour obtenir les beans Spring.

Bean Spring

Un Bean Spring n’a rien de spécial, c’est tout objet dans le framework Spring que nous initialisons via le conteneur Spring. N’importe quelle classe Java POJO normale peut être un Bean Spring si elle est configurée pour être initialisée via le conteneur en fournissant des informations de métadonnées de configuration.

Portées des Beans Spring

Il existe cinq portées définies pour les Spring Beans.

  1. singleton – Une seule instance du bean sera créée pour chaque conteneur. C’est la portée par défaut des beans Spring. Lorsque vous utilisez cette portée, assurez-vous que le bean n’a pas de variables d’instance partagées, sinon cela pourrait entraîner des problèmes d’incohérence des données.
  2. prototype – Une nouvelle instance sera créée chaque fois que le bean est demandé.
  3. request – C’est la même chose que la portée prototype, cependant elle est destinée à être utilisée pour les applications web. Une nouvelle instance du bean sera créée pour chaque requête HTTP.
  4. session – Un nouveau bean sera créé pour chaque session HTTP par le conteneur.
  5. global-session – Ceci est utilisé pour créer des beans de session globaux pour les applications Portlet.

Le Framework Spring est extensible et nous pouvons également créer nos propres portées. Cependant, la plupart du temps, nous nous contentons des portées fournies par le framework.

Configuration des Beans Spring

Le Framework Spring propose trois façons de configurer les beans à utiliser dans l’application.

  1. Configuration basée sur l’annotation – En utilisant les annotations @Service ou @Component. Les détails de portée peuvent être fournis avec l’annotation @Scope.
  2. Configuration basée sur XML – En créant un fichier XML de configuration Spring pour configurer les beans. Si vous utilisez le framework Spring MVC, la configuration basée sur XML peut être chargée automatiquement en écrivant un peu de code de base dans le fichier web.xml.
  3. Configuration basée sur Java – À partir de Spring 3.0, nous pouvons configurer les beans Spring à l’aide de programmes Java. Certaines annotations importantes utilisées pour la configuration basée sur Java sont @Configuration, @ComponentScan et @Bean.

Projet d’exemple de Spring IoC et de bean Spring

Regardons les différents aspects du conteneur Spring IoC et des configurations de bean Spring avec un projet Spring simple. Pour mon exemple, je crée un projet Spring MVC dans Spring Tool Suite. Si vous êtes nouveau dans Spring Tool Suite et Spring MVC, veuillez lire Tutoriel Spring MVC avec Spring Tool Suite. La structure finale du projet ressemble à l’image ci-dessous. Regardons les différents composants du conteneur Spring IoC et du projet de bean Spring un par un.

Configuration de bean Spring basée sur XML

MyBean est une classe 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;
	}
	
}

Fichier de configuration Spring XML

Code 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>

Remarquez que MyBean est configuré en utilisant l’élément bean avec une portée singleton.

Configuration de bean Spring basée sur les annotations

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;
	}
	
}

MonAnnotatedBean est configuré en utilisant @Service et la portée est définie sur Request.

La classe Spring IoC Controller

La classe HomeController gérera les requêtes HTTP pour la page d’accueil de l’application. Nous injecterons nos beans Spring dans cette classe de contrôleur via le conteneur 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";
	}
	
}

Descripteur de déploiement

Nous devons configurer notre application pour le framework Spring afin que les métadonnées de configuration soient chargées et que le contexte soit initialisé.

<?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>

Presque toute la configuration ci-dessus est un code généré automatiquement par l’outil STS.

Exécuter l’application exemple de bean Spring IoC

Maintenant, lorsque vous lancerez l’application Web, la page d’accueil se chargera et dans la console, les journaux suivants seront imprimés lorsque vous rafraîchirez la page plusieurs fois.

MyBean hashcode=118267258
MyAnnotatedBean hashcode=1703899856
MyBean hashcode=118267258
MyAnnotatedBean hashcode=1115599742
MyBean hashcode=118267258
MyAnnotatedBean hashcode=516457106

Remarquez que MyBean est configuré pour être un singleton, donc le conteneur renvoie toujours la même instance et le code de hachage est toujours le même. De même, pour chaque requête, une nouvelle instance de MyAnnotatedBean est créée avec un code de hachage différent.

Configuration des Beans Spring Basée sur Java

Pour les applications autonomes, nous pouvons utiliser une configuration basée sur des annotations aussi bien qu’une configuration basée sur XML. La seule exigence est d’initialiser le contexte quelque part dans le programme avant de l’utiliser.

package com.journaldev.spring.main;

import java.util.Date;

public class MyService {

	public void log(String msg){
		System.out.println(new Date()+"::"+msg);
	}
}

MyService est une simple classe java avec quelques méthodes.

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 classe de configuration basée sur des annotations qui sera utilisée pour initialiser le conteneur 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 vous recherchez une configuration basée sur XML, créez simplement le fichier de configuration XML de Spring, puis initialisez le contexte avec le fragment de code suivant.

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                "applicationContext.xml");
        MyService app = context.getBean(MyService.class);

C’est tout pour le tutoriel d’exemple Spring IoC, les portées de Spring Bean et les détails de configuration. Téléchargez le projet d’exemple Spring IoC et Spring Bean à partir du lien ci-dessous et jouez avec pour mieux le comprendre.

Téléchargez le Projet de Beans Spring

Référence : Page Spring.IO pour IOC

Source:
https://www.digitalocean.com/community/tutorials/spring-ioc-bean-example-tutorial