Your browser doesn't support the features required by impress.js, so you are presented with a simplified version of this presentation.

For the best experience please use the latest Chrome, Safari or Firefox browser.

Le framework Spring

Historique

  • 0.9 - Première version !
  • 1.0 - Optimisations diverses
  • 2.0 - Simplification des configurations XML, support de Groovy, de JPA
  • 2.5 - Configuration par annotations, support de Java 6, auto-détection des composants
  • 3.0 - Spring expression language, support des bases de données intégrées, validation des model, support de REST
  • 3.1 - Profils de beans, abstraction de cache
  • 4.0 - Support de Java 8, apparition de Spring Boot
  • 4.2 - Améliorations du Code Container et de la couche d'accès aux données
  • 4.3 - Améliorations du cache et des modules webs
  • 5.0 - Spring WebFlux, support de Kotlin

Les différents projets

Les concepts

L'inversion de contrôle (IoC)

L'injection de dépendances (DI)

  • Réduction au maximum des dépendances entre les composants logiciels
  • Maintenance et évolutions plus maitrisées
  • Utilisation possible d'implémentations différentes d'un composant sans tout modifier.
  • Plus de gestion manuelle du cycle de vie des composants.
  • Patterns de développement comme le singleton utilisables très facilement.
  • Code plus facile à tester (mocks), à lire et à réutiliser.
  • Ajout d'une dépendance à un framework potentiellement lourd ?
  • Perte de contrôle ?

Spring Core

Beans
Core
Context
SpEL
Core et Beans sont les modules qui implémentent l'inversion de contrôle et l'injection de dépendences.
Context est une sorte de registre permettant de construire, stocker et injecter les différents composants de votre application.
SpEL ou Spring Expression Language permet de consulter et manipuler le graph d'objets à l'exécution.

Les Beans

  • Un bean doit être décrit dans une configuration de bean à fournir au conteneur Spring.
  • Lorsqu'il y a des dépendances entre des beans, Spring lie ces derniers entre eux par injection.
  • Les déclarations de beans permettent aux beans d'être instantiés, stockés, gérés et détruits par le conteneur Spring via l'ApplicationContext.

Les configurations de Beans

  • Eléments à définir
  • La classe
  • Le nom
  • Le scope
  • Les arguments du constructeur et les autres propriétés
  • L'initialisation/destruction
//Soit la classe suivante que l'on faire gérer par Spring
public class BeanExemple{
  private String msg;
  private String nom;
  public void getNom(){return nom;}
  public void setNom(String n){nom = n;}
  public BeanExemple(String m){msg=m;}
  public void init() {}
  public void cleanup() {}
}

<!-- applicationContext.xml -->
<?xml version = "1.0" encoding = "UTF-8"?>
<beans xmlns = "..." ... >
<bean name="beanExemple" class="com.ipiecoles.BeanExemple"
  scope="prototype" init-method="init" destroy-method="cleanup">
  <constructor-arg value = "Hello "/><!-- OU -->
  <constructor-arg index = "0" value = "Hello "/><!-- OU -->
  <constructor-arg type = "java.lang.String" value = "Hello "/>
  <property name = "nom" value = "World"/>
</bean>
</beans>
@Configuration
public class SpringConfig {
  @Bean(initMethod = "init", destroyMethod = "cleanup")
  @Scope("prototype")
  public BeanExemple beanExemple(){
    BeanExemple be = new BeanExemple("Hello ");
    be.setNom("World");
    return be;
  }
}

L'injection de beans

public class BeanExemple{
  private AutreBeanEx autreBean;
  public void getAutreBean(){ return autreBean; }
  public void setAutreBean(String b){
    autreBean = b;
  }
}

<!-- applicationContext.xml -->
<?xml version = "1.0" encoding = "UTF-8"?>
<beans xmlns = "..." ... >
  <bean name="autreBean" class="com.ipiecoles.AutreBeanEx"/>

  <bean name="beanExemple" class="com.ipiecoles.BeanExemple">
    <property name="autreBean" ref="autreBean"/>
  <bean/>
</beans>
@Configuration
public class SpringConfig {
  @Bean 
  public BeanExemple beanExemple(){
    BeanExemple b = new BeanExemple();
    b.setAutreBean(autreBeanEx());
  }
  @Bean 
  public AutreBeanEx autreBeanEx(){
    return new AutreBeanEx();
  }
}

ApplicationContext

package com.ipiecoles;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.*;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
   public static void main(String[] args) {
        //Configuration Java
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        //OU Configuration XML
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

        BeanExemple be = ctx.getBean(BeanExemple.class);
        //be peut être utilisé dans ce main et les beans déclarés
        //dans la configuration ont été intégrés dans le conteneur
   }
}

Simplifier et automatiser

//Annotation des beans à gérer par Spring avec @Component
//(seulement pour les singletons)
@Component
public class BeanExemple{
  //Injection d'un bean avec @Autowired, l'injection se fait par
  //type. Attention, si deux beans existent du même type,
  //cette injection échouera !
  @Autowired
  private AutreBeanEx autreBean;
}

@Component
public class AutreBeanEx{
}
@Configuration
//L'annotation @ComponentScan permet de dire à Spring
//de chercher les beans dans toutes les classes de ce
//ce package.
@ComponentScan(basePackages = "com.ipiecoles")
public class SpringConfig {

}

Cas particuliers (1/2)

@Component
public class BeanExemple{
  //Utiliser @Resource pour injecter explicitement par nom
  @Resource(name = "autreBean1")
  private AutreBeanEx autreBean1;
  //Ici @Autowired fonctionne car @Primary a été mis
  //sur le bean principal
  @Autowired
  private AutreBeanEx autreBean;
}

public class AutreBeanEx{
  private String nom;
  private AutreBeanEx(String n){nom = n;}
}
@Configuration
@ComponentScan(basePackages = "com.ipiecoles")
public class SpringConfig {
    @Bean(name = "autreBean1")
    public AutreBeanEx autreBean1(){
        return new AutreBeanEx("Hello");
    }
    @Bean(name = "autreBean")
    //L'annotation @Primary permet de lever le doute
    //lorsque plusieurs beans ont le même type.
    @Primary
    public AutreBeanEx autreBean(){
        return new AutreBeanEx("World");
    }
}

Cas particuliers (2/2)

public class AutreBeanEx{
  @PostConstruct //remplace init-method
  public void init() {
      // Instructions à exécuter après l'instanciation
  }

  @PreDestroy //remplace destroy-method
  public void cleanup() {
      // Instructions à exécuter avant la destruction
  }
}
@Configuration
public class SpringConfig {
    @Bean
    @Scope("prototype")
    public AutreBeanEx autreBean(){
        return new AutreBeanEx();
    }
}

Les fichiers .properties

#app.properties
ipi.nom=IPI
ipi.message=Hello

<beans>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations" value="classpath:app.properties"/>
</bean>
<!-- OU -->
<context:property-placeholder location="classpath:app.properties"/>

<bean id="beanExemple" class="com.ipiecoles.BeanExemple">
    <property name="nom" value="${ipi.nom}"/>
    <property name="message" value="${ipi.message}"/>
</bean>
</beans>
@Configuration
@PropertySource("classpath:app.properties")
public class SpringConfig {
    @Value("${ipi.nom}")
    private String nom;
    @Value("${ipi.message}")
    private String message;
    @Bean(name = "beanExemple")
    public BeanExemple beanExemple(){
        return new
          BeanExemple(message, nom);
    }
}

Spring Boot

  • Démarrer très rapidement le développement de votre application (notamment les applications web) sans être ralenti par des éléments de configuration
  • Profiter de librairies tierces directement disponibles mais facilement désactivables ou remplaçables par l'ajout explicite de dépendances.
  • Externaliser la configuration dans des fichiers de configurations (.properties ou YAML).
  • Avoir des fonctionnalités supplémentaires comme des serveurs intégrés, du monitoring, des vérifications au niveau de la santé et de la sécurité de votre application...

La gestion des dépendances

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.4.RELEASE</version>
		<relativePath/>
	</parent>
	<groupId>com.ipiecoles.java</groupId>
	<artifactId>java240</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>java240</name>
	<description>TP sur Spring</description>
	<dependencies>
		<!-- Ajout de dépendances starter en fonction des besoins-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<!-- Dépendance à MySQL => désactivation de la BDD intégrée et configuration optimisée pour MySQL-->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<!-- Autres dépendances déclarées de manière classique-->
	</dependencies>
</project>

L'application

package com.example.myapplication;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
//équivalent à @Configuration @EnableAutoConfiguration @ComponentScan
public class Application {

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}

}

Application Web

  • Servir automatiquement des ressources statiques.
  • Customiser aisément des convertisseurs automatiques des objets manipulés dans les requêtes/réponses HTTP en JSON ou en XML
  • Auto-configurer des moteurs de templates FreeMarker, Groovy, Thymeleaf ou Mustache (si dépendance présente). A noter que Spring Boot déconseille l'utilisation des JSP...
  • Déployer automatiquement l'application dans un serveur Tomcat intégré

Application en mode console

import org.springframework.boot.*;
import org.springframework.stereotype.*;

@Component
public class MyBean implements CommandLineRunner {

    @Autowired
    private BeanExemple beanExample;

    public void run(String... args) {
        // Point d'entrée de votre application en ligne de commande.
    }

}