Que fait le framework Spring? Devrais-je l'utiliser? Pourquoi ou pourquoi pas?

237

Je lance donc un tout nouveau projet en Java et envisage d’utiliser Spring. Pourquoi je considère le printemps? Parce que beaucoup de gens me disent que je devrais utiliser le printemps! Sérieusement, chaque fois que j'ai essayé d'amener les gens à expliquer ce qu'est exactement le printemps ou ce qu'il fait, ils ne peuvent jamais me donner une réponse directe. J'ai consulté les introductions sur le site SpringSource. Elles sont très compliquées ou sont axées sur des didacticiels. Aucune d'elles ne me donne une bonne idée de la raison pour laquelle je devrais l'utiliser, ou de la manière dont cela facilitera ma vie. Parfois, les gens parlent d’injection «dépendance», ce qui me rend encore plus confus, car j’ai une compréhension différente de ce que signifie ce terme.

Quoi qu'il en soit, voici un peu de mon expérience et de mon application:

Développé depuis un certain temps en Java, développement Web back-end. Oui, je fais une tonne de tests unitaires. Pour faciliter cela, je crée généralement (au moins) deux versions d'une méthode: une qui utilise des variables d'instance et une qui utilise uniquement des variables qui sont transmises à la méthode. Celui qui utilise des variables d'instance appelle l'autre, en fournissant les variables d'instance. Quand vient le temps de tester les unités, j'utilise Mockito pour simuler les objets puis passer des appels à la méthode qui n'utilise pas de variables d'instance. C'est ce que j'ai toujours compris par "injection de dépendance".

Mon application est assez simple, d'un point de vue CS. Petit projet, 1-2 développeurs pour commencer. Il s'agit principalement d'opérations de type CRUD avec un groupe de recherches. Fondamentalement, un ensemble de services Web RESTful, ainsi qu'un serveur Web, puis éventuellement des clients mobiles. Je pense faire du front-end en HTML / CSS / JS / JQuery, donc aucun projet réel d’utiliser JSP. Utiliser Hibernate comme ORM et Jersey pour implémenter les services Web.

J'ai déjà commencé à coder et je suis vraiment impatient d'obtenir une démo sur laquelle je peux faire le tour et voir si quelqu'un veut investir. Il est donc évident que le temps presse. Je comprends que Spring a une courbe d'apprentissage assez longue. De plus, il semble nécessiter toute une configuration XML, ce que j'essaie généralement d'éviter comme la peste. Mais si cela peut me rendre la vie plus facile et (surtout) si cela peut accélérer le développement et les tests, je suis prêt à mordre la balle et à apprendre le printemps.

Donc s'il vous plait. Éduque moi. Devrais-je utiliser le printemps? Pourquoi ou pourquoi pas?

sang-froid
la source
10
Je pense que vous devez vraiment l'essayer vous-même pendant un certain temps pour voir si vous l'aimez et si cela convient à votre projet. Personnellement je déteste ça.
Richard
1
Bien que vous puissiez utiliser XML ou des annotations; Gardez à l'esprit que Spring adopte une convention sur la mentalité de configuration. Ce n'est pas nécessairement une liste des articles que vous avez à répondre.
Aaron McIver
14
S'il est vrai que cette question est plutôt large, je pense qu'elle devrait rester ouverte. Je l'ai lu comme suit: "Quels avantages Spring offre-t-il pour un projet de taille moyenne?", Et c'est une bonne question.
Sleske
1
Je recommande fortement de lire mon livre technique préféré: Spring in Action, troisième édition de Craig Walls. C'est une excellente lecture qui changera votre façon de programmer.
alfredaday
4
Vu Enterprise Java, il est plus facile de répondre à ce que Spring ne fait pas ...
m3th0dman

Réponses:

108

Que fait le framework Spring? Devrais-je l'utiliser? Pourquoi ou pourquoi pas?

Spring est un framework qui vous aide à "câbler" différents composants ensemble. Il est particulièrement utile dans les cas où vous avez beaucoup de composants et que vous pouvez décider de les combiner de différentes manières ou souhaitez faciliter la permutation d'un composant par un autre en fonction de différents paramètres ou environnements.

C'est ce que j'ai toujours compris par "injection de dépendance".

Je suggérerais une définition différente:

"Concevez vos objets de manière à ce qu'ils s'appuient sur une force extérieure pour leur fournir ce dont ils ont besoin, en espérant que ces dépendances soient toujours injectées avant que quiconque ne leur demande de commencer à faire leur travail habituel."

Comparez cela avec: "Chaque objet est responsable de sortir et de trouver tout et tout ce dont il a besoin au démarrage."

il semble que cela nécessite tout un tas de configuration XML

Eh bien, la plupart des éléments XML (ou basés sur des annotations) indiquent à Spring des éléments tels que:

  • Quand quelqu'un demande "HammerStore", je veux que vous créiez une instance de example.HammerStoreet la renvoient. Mettez l'instance en cache pour la prochaine fois, car il ne doit y avoir qu'un seul magasin.
  • Quand quelqu'un demande "SomeHammer", je veux que vous vous demandiez un "HammerStore" et que vous retourniez le résultat de la makeHammer()méthode du magasin . Ne cachez pas ce résultat.
  • Quand quelqu'un demande "SomeWrench", je veux que vous créiez une instance de example.WrenchImpl, utilisez le paramètre de configuration gaugeAmountet placez-le dans la setWrenchSize()propriété de l'instance . Ne cachez pas le résultat.
  • Quand quelqu'un demande "LocalPlumber", je veux vous créer une instance de example.PlumberImpl. Mettez la chaîne "Pedro" dans sa setName()méthode, insérez un "SomeHammer" dans sa setHammer()méthode et un "SomeWrench" dans sa setWrench()méthode. Renvoie le résultat et le cache pour plus tard, car nous n'avons besoin que d'un seul plombier.

De cette manière, Spring permet à vos composants de connexion, de les étiqueter, de contrôler leur cycle de vie / mise en cache et de modifier le comportement en fonction de la configuration.

Pour faciliter le test, je crée généralement (au moins) deux versions d'une méthode: une qui utilise des variables d'instance et une qui utilise uniquement les variables transmises à la méthode.

Cela ressemble à beaucoup de frais généraux pour pas beaucoup d'avantages pour moi. Au lieu de cela, assurez-vous que vos variables d’instance ont une protectedvisibilité ou une visibilité du package et localisez les tests unitaires dans le même com.mycompany.whateverpackage. De cette façon, vous pouvez inspecter et modifier les variables d'instance à tout moment pendant les tests.

Darien
la source
65

Tout d’abord, qu’est-ce que l’injection de dépendance?

Facile. Vous avez une classe, un champ privé (défini sur null) et vous déclarez un opérateur public fournissant la valeur de ce champ. En d'autres termes, la dépendance de la classe (le champ) est injectée par une classe externe (via le setter). C'est ça. Rien de magique.

Deuxièmement, Spring peut être utilisé sans XML (ou très peu)

Si vous utilisez Spring 3.0.5.GA ou une version ultérieure, vous pouvez utiliser le support d’injection de dépendance de JDK6 +. Cela signifie que vous pouvez câbler des dépendances en utilisant les annotations @Componentet @Resource.

Pourquoi utiliser le printemps du tout?

De toute évidence, l’injection de dépendance favorise les tests unitaires très faciles, car toutes vos classes disposent de réglages pour les dépendances importantes, qui peuvent être facilement simulées à l’aide de votre framework moqueur préféré pour fournir le comportement requis.

Cela dit, Spring fournit également de nombreux modèles qui servent de classes de base pour faciliter l’utilisation des technologies standard JEE. Par exemple, JdbcTemplate fonctionne bien avec JDBC, JpaTemplate fait de bonnes choses avec JPA, JmsTemplate rend JMS assez simple. Le RestTemplate est tout simplement génial par sa simplicité. Par exemple:

RestTemplate restTemplate = new RestTemplate();
MyJaxbObject o = restTemplate.getForObject("https://secure.example.org/results/{param1}?param2={param2}",MyJaxbObject.class,"1","2");

et tu as fini. Les paramètres sont injectés et il vous suffit de fournir des annotations JAXB pour MyJaxbObject. Cela ne devrait pas prendre de temps si vous les avez générés automatiquement à partir d'un XSD à l'aide du plug-in Maven JAXB. Notez qu’il n’y avait aucun casting, ni besoin de déclarer un commissaire. Tout est fait pour vous.

Je pourrais m'embrouiller pour toujours sur les merveilles du printemps, mais la meilleure chose à faire est peut-être d'essayer un simple pic de code où vous essayez de câbler un service Web RESTful pour extraire des données d'un DAO injecté qui prend en charge les transactions.

Gary Rowe
la source
4
ouais RestTemplate est vraiment génial. J'ai environ 100 lignes de code que je peux jeter et remplacer par 2-3 lignes.
Kevin
11
NIPPICK: Dependency Injection inclut également l’approche basée sur le constructeur. Vous n'avez pas nécessairement besoin d'avoir des setters.
Darien
28

Tout d'abord, votre compréhension de l'injection de dépendance n'est pas fondamentalement fausse, mais bien différente de ce que la plupart des gens veulent dire lorsqu'ils utilisent ce terme. Ce que vous décrivez est un moyen plutôt étrange et non conventionnel d’atteindre la testabilité. Je vous conseillerais de vous en éloigner, car les autres développeurs seraient plutôt perplexes devant ce type de code.

L'injection de dépendance telle qu'elle est généralement comprise (et implémentée par Spring) signifie que les dépendances dont dispose une classe (par exemple, une source de données JDBC) ne sont pas extraites par la classe elle-même, mais "injectées" par un conteneur lors de la création de l'instance. Donc, vous n'avez pas deux versions de chaque méthode qui utilise la source de données; Au lieu de cela, vous avez une configuration d'injection de dépendance où la "vraie" source de données est injectée et une configuration où une maquette est injectée. Ou, si l'injection se produit via le constructeur ou un getter, le code de test peut effectuer l'injection explicitement.

Deuxièmement, Spring n’est pas simplement une injection de dépendance, bien que ce soit sa fonctionnalité principale. Il fournit également des transactions déclaratives, la planification des tâches, l’authentification et de nombreuses autres fonctionnalités (notamment une infrastructure Web MVC à part entière) dont vous pourriez avoir besoin. Il existe d'autres frameworks offrant les mêmes fonctionnalités mais, à l'exception de Spring, seul Java EE les intègre tous.

Michael Borgwardt
la source
OP comprend bien la DI
Basilevs
19

Pourquoi voulez-vous utiliser Spring? Vous pouvez le lire à l’ adresse http://www.wrox.com/WileyCDA/Section/Why-Use-the-Spring-Framework-.id-130098.html

En résumé :

  • Les applications J2EE ont tendance à contenir des quantités excessives de code "plomberie". De nombreuses revues de code révèlent à maintes reprises une forte proportion de code qui ne fait rien: code de recherche JNDI, objets de transfert, blocs try / catch pour acquérir et libérer des ressources JDBC. . . . La rédaction et la maintenance d'un tel code de plomberie constituent une lourde charge pour les ressources qui devraient être concentrées sur le domaine d'activité de l'application.

  • De nombreuses applications J2EE utilisent un modèle d'objet distribué lorsque cela est inapproprié. C’est l’une des principales causes de code excessif et de duplication de code. C'est également faux conceptuellement dans de nombreux cas; Les applications distribuées en interne sont plus complexes que les applications co-localisées et souvent beaucoup moins performantes. Bien sûr, si vos exigences métier imposent une architecture distribuée, vous devez implémenter une architecture distribuée et accepter le compromis qui en découle (et Spring propose des fonctionnalités pour vous aider dans de tels scénarios). Mais vous ne devriez pas le faire sans une raison impérieuse.

  • Le modèle de composant EJB est excessivement complexe. EJB a été conçu pour réduire la complexité lors de l’implémentation de la logique applicative dans les applications J2EE. il n'a pas réussi à atteindre cet objectif dans la pratique.

  • EJB est trop utilisé. EJB a été essentiellement conçu pour les applications transactionnelles distribuées en interne. Bien que presque toutes les applications non triviales soient transactionnelles, la distribution ne devrait pas être intégrée au modèle de composant de base.

  • De nombreux "modèles de conception J2EE" ne sont pas, en fait, des modèles de conception, mais des solutions de contournement pour les limitations technologiques. La surutilisation de la distribution et l'utilisation d'API complexes tels que les EJB ont généré de nombreux modèles de conception douteux; il est important de les examiner de manière critique et de rechercher des approches plus simples et plus productives.

  • Les applications J2EE sont difficiles à tester. Les API J2EE, et en particulier le modèle de composant EJB, ont été définis avant le démarrage du mouvement agile. Ainsi, leur conception ne tient pas compte de la facilité des tests unitaires. Grâce aux API et aux contrats implicites, il est étonnamment difficile de tester des applications basées sur EJB et de nombreuses autres API J2EE en dehors d'un serveur d'applications. Cependant, les tests unitaires effectués en dehors d'un serveur d'applications sont essentiels pour obtenir une couverture de tests élevée et reproduire de nombreux scénarios de défaillance, tels que la perte de connectivité à une base de données. Il est également essentiel de veiller à ce que les tests puissent être exécutés rapidement pendant le processus de développement ou de maintenance, en minimisant les temps non productifs d’attente du redéploiement.

  • Certaines technologies J2EE ont tout simplement échoué. Le principal responsable est les beans entity, qui se sont révélés tout à fait désastreux pour la productivité et leurs contraintes d'orientation des objets.

Rudy
la source
13

Auparavant, nous écrivions des applications et des services Web simples, efficaces et rapides utilisant uniquement le noyau Java, les servlets et JSP, les langages HTML et XML, ainsi que l'API JDBC. C'était assez bon. JUnit était un bon outil à tester. Nous nous sommes reposés facilement que notre code a fonctionné.

Hibernate est venu simplifier le SQL et permettre un véritable mappage des tables de la base de données avec des objets Java, ce qui permet de refléter les relations hiérarchiques dans le mappage de relations entre objets ou ORM, comme nous l'appelons. Je l'ai aimé. En particulier, nous n'avons pas eu à mapper le ResultSet dans un objet Java ou un type de données.

Struts est venu ajouter le modèle Model View Controller à nos applications Web, c'était bien.

Les EJB représentaient un énorme surcoût et la douleur et les annotations donnaient l'impression que le code ressemblait à une éraflure de poulet. Maintenant, le printemps s'est abattu sur nous, innocents. Cela me semble exagéré.

Par exemple, nous emballons maintenant notre simple URL jdbc, utilisateur, passons d’abord dans jdbc.properties, puis dans les propriétés hibernate, puis dans les beans Spring pour la troisième fois!

Par rapport à tout cela, envisagez d’obtenir une connexion là où vous en avez besoin. C’est aussi simple que cela est montré ci-dessous en java pur. C’est ce que nous faisons en réalité après avoir traversé tout ce qui se passe dans le vent avec Spring:

Connection connection = DriverManager.getConnection(url, user, pass);

Cela va de soi en soi qu’il s’agit d’un gros tour en rond qui permet de faire une chose simple et rapide sans aucun autre grand avantage. C'est comme emballer des tonnes et des tonnes de papier cadeau autour d'un joli petit cadeau qui est tout ce que vous conservez de toute façon.

Un autre exemple est une mise à jour par lot. Avec Spring, il est compliqué de faire intervenir plusieurs classes et interfaces avant de pouvoir utiliser JdbcTemplate pour effectuer une mise à jour par lots. Avec plain jdbc c'est tout simplement:

Statement statement = connection.createStatement();
statement.addBatch(sqlquery);
statement.executeBatch();

Je ne peux pas être plus simple ou plus rapide que ça.

Je ne supporte pas ce cadre. Pardon. Qui sur terre veut des injections chaque fois qu'ils ont besoin de quoi que ce soit?

Uma
la source
6
Ce code est simple, mais où est définie votre gestion de la transposition et comment la testez-vous? Les deux choses sont simplifiées par le printemps. En outre, votre code Java est directement lié à une connexion à une base de données. À moins que vous stockiez les URL de connexion et les mots de passe en externe, cela est également simplifié par spring.
NimChimpsky
+1 pour cette réponse, pour répondre au commentaire ci-dessus, man utilise vos propres modèles de conception de poids léger (GOF), singleton pour le regroupement de connexions, une classe proxy qui fournit sql (chaîne) et des valeurs (tableau) à l'objet de base de données (quelle méthode , dépend de la méthode http), dbobject gère le regroupement de connexions, les transactions, etc., en exécutant une requête suivie par la libération. Utilisation unique dans tous les modules, personne n’a besoin d’un code de plaque de chaudière excessif. point bonus avec paramétrage des tests unitaires sur la classe proxy et dbobject.
user2727195
Découvrez Spring-Data-JPA! Annoter un pojo dans une entité, implémenter une interface et définir des signatures de méthode à l'aide de noms raisonnables, tels que findHammerByWeight (), et spring implémente les méthodes pour vous, vous offrant ainsi un référentiel injectable que vous pouvez utiliser dans tous vos autres classes de services ou de contrôleurs. .
mancini0
13

Que fait le framework Spring?

Le printemps est comme aujourd'hui non seulement, ce qui était connu comme un simple cadre, c'est un écosystème complet.

Thèmes couverts par l'écosystème printanier:

  • Cadre Spring (par exemple, injection de dépendance, AOP, etc.)

  • Nuage de printemps

  • Données de printemps

  • Sécurité de printemps

  • Lot de printemps

  • Printemps Social

Voir ici pour une couverture complète de l'écosystème. Il est possible de sélectionner des projets, de sorte que vous puissiez utiliser Google Guice pour DI et, par exemple, Spring Security pour gérer des éléments liés à la sécurité. Vous n'avez pas à acheter l'ensemble de l'écosystème.

Le cadre de printemps lui-même couvre aujourd'hui principalement

  • Injection de dépendance

  • Programmation orientée aspect incluant la gestion déclarative des transactions de Spring

  • Application Web Spring MVC et infrastructure de services Web RESTful

  • Support de base pour JDBC, JPA, JMS

Source spring.io

En règle générale, vous pouvez dire que Spring est un ensemble de modèles et de pratiques implémentés dans le code, qui peuvent aider à améliorer ou à accélérer le cycle de développement de vos applications.

Ce qui lui est le plus connu, c’est ses capacités dans le domaine de l’ injection de dépendances . Spring lui-même a ce qu’on appelle Inversion du conteneur de contrôle ou conteneur IoC court ou même plus court du conteneur (pour lequel "ressort" est parfois utilisé).

Qu'est-ce que l'injection de dépendance?

L'injection de dépendance signifie que votre objet reçoit chaque dépendance par rapport à d'autres objets via un mécanisme externalisé.

Dites, vous avez une voiture, la manière typique, il est implémenté est:

public class Car {

    Engine e;

    public Car() { 
        e = new Engine(); 
    }

}

L'objet de voiture dépend d'un moteur. Étant donné que le moteur est implémenté en tant que membre d'une voiture, il ne peut pas être échangé pour un moteur d'essai, par exemple.

Maintenant, l' injection de dépendance entre en jeu:

public class Car {

    Engine e;

    public Car(Engine e) { 
        this.e = e; 
    }

}

Après cela, vous pouvez changer de moteur. Ce que vous voyez ci-dessus s'appelle injection de constructeur . Il existe d'autres types tels que, par exemple, setter -injection ou method -injection. Comment Spring vous aide-t-il avec cela? Spring lui permet de marquer les composants à injecter avec l'annotation @Autowiredet effectue le câblage de l'objet injecteed automatiquement - il est probable que le composant que vous souhaitez injecter possède lui-même des dépendances. Les injectables - pour ainsi dire - sont marqués via@Component

public class Car {

    Engine e;

    @Autowired
    public Car(Engine e) { 
        this.e = e; 
    }

}

Mais ce n’est qu’une des nombreuses fonctionnalités offertes par Spring.

Devrais-je utiliser le printemps? Pourquoi ou pourquoi pas?

Comme le printemps n’est pas très intrusif et offre de nombreuses aides, vous devriez envisager de l’utiliser. Spring Boot est particulièrement attrayant pour les nouveaux projets . start.spring.io offre un facile à utiliser clicks -interface pour générer un modèle de projet pour commencer. Il est même possible d'utiliser curlpour récupérer un modèle:

curl start.spring.io

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

:: Spring Initializr ::  https://start.spring.io

This service generates quickstart projects that can be easily customized.
Possible customizations include a project's dependencies, Java version, and
build system or build structure. See below for further details.

The services uses a HAL based hypermedia format to expose a set of resources
to interact with. If you access this root resource requesting application/json
as media type the response will contain the following links:
+-----------------+-----------------------------------------+
| Rel             | Description                             |
+-----------------+-----------------------------------------+
| gradle-build    | Generate a Gradle build file            |
| gradle-project  | Generate a Gradle based project archive |
| maven-build     | Generate a Maven pom.xml                |
| maven-project * | Generate a Maven based project archive  |
+-----------------+-----------------------------------------+

...

D'autre part, les frameworks tels que spark ou dropwizard constituent également un bon point de départ pour la création rapide d'applications Web.

Thomas Junk
la source
1
Réponse très informative!
GOXR3PLUS
D'accord, très bonne réponse. OP, je compatis avec vous. Plusieurs personnes m'ont également montré des démos de Spring dans lesquelles ils "simplifient" le code en ajoutant un fichier XML et 2 couches d'indirection afin de pouvoir appeler le constructeur d'une classe :) Vous devez vraiment plonger dans ou aller à un vraiment bonne présentation et finalement, il deviendra clair où les avantages et les inconvénients sont
Adam Hughes
4

C'est un framework écrit en Java avec beaucoup d'éléments inclus pour rendre votre application web fonctionnelle (par exemple, support pour l'internationalisation). C'est également un bon moyen de structurer votre application en couches. Utilisez-le, cela vous fera gagner beaucoup de temps à long terme.

Un bon livre pour en apprendre davantage sur Spring est: Expert Spring MVC et Web Flow

Bernard
la source