Contexte: application Web
Je n'avais jamais utilisé Spring auparavant, mais selon la documentation Spring, tous les haricots sont singleton
, à moins que nous ne les déclarions comme prototype
.
Normalement, j'instancie un nouveau DAO lorsqu'il y a un appel à la couche service/entreprise . S'il s'agit d'un service RESTfull, j'instancie la quasi-totalité des objets qui dépendent de l'appel.
Je peux annoter les classes d'accès aux données avec @Repository
et je peux aussi utiliser @Service
pour les classes de couche de service.
Donc, mes classes avec les annotations ci-dessus sont singleton
par défaut . Il y a une annotation @Scope
que nous pouvons déclarer comme prototype, mais personne ne semble le faire .
new Object();
à chaque foissingleton
Mes questions sont,
@Repository
est singleton
, comment gère-t-il la sécurité des threads quand rien de tel n’est traité? (Supposons que cela soit fait par les mandataires de printemps)@Repository
suffit ou ajouter @Scope('prototype')
serait préférable?@Scope('prototype')
avec @Repository
(selon les tutoriels, les blogs, etc.). Y a-t-il une raison bien connue?Merci
Vous avez raison - dans le monde {Spring} _, la plupart des haricots sont des singletons.
- La façon dont j'ai utilisé auparavant (créer une nouvelle instance à chaque fois) est incorrecte?
Ce n'est pas incorrect car cela fonctionne. Le problème, c’est que vous instanciez une nouvelle instance de DAO à chaque requête - dans certains cas, cela peut coûter cher, et de toute façon, cela n’a aucun sens - pourquoi auriez-vous besoin de nombreuses instances de DAO?. D'autre part, non seulement crée un singleton, mais injecte également des DAO dans des services ou d'autres DAO, etc. c'est-à-dire fait beaucoup de travail pour vous
- Si @Repository est un singleton, comment gère-t-il la sécurité des threads lorsqu'aucun problème de ce type n'est résolu? (Supposons que cela soit fait par les mandataires de printemps)
Lorsque vous écrivez un bean @Repository, vous devez normalement y injecter un DataSource ou un EntityManager. La méthode DataSource.getConnection () doit être thread-safe. En ce qui concerne EntityManager, Spring injectera un proxy qui se comportera différemment pour différents threads, c'est-à-dire que différents threads ne partageront pas la même session JPA.
- Quelle est la meilleure pratique, @Repository est suffisant ou l’ajout de @Scope ('prototype') serait préférable?
La meilleure pratique (ou plutôt l’approche la plus répandue) consiste à utiliser simplement @Repository
- Je ne vois personne utiliser @Scope ('prototype') avec @Repository (d'après les tutoriels, les blogs, etc.). Y a-t-il une raison bien connue?
La raison en est qu'il n'y a aucun profit à créer plusieurs instances de beans @Repository.
- Et si ma classe DAO est accédée par plusieurs grands nombres de threads à très haute fréquence? (Ceci est celui que je concerne le plus)
Ici encore, singleton est préférable à la création d'un nouvel objet pour chaque requête. Évitez simplement la synchronisation redondante pour que vos threads ne se bloquent pas sur certains moniteurs
Non, mais il est beaucoup plus difficile de faire des tests unitaires, ce qui est l’injection de dépendance. En injectant un DAO dans un service, vous pouvez facilement tester le service en injectant un DAO factice pendant le test. Ce n'est pas possible si le service crée son propre DAO.
Un référentiel est généralement complètement sans état, à l'exception d'un gestionnaire d'entités, d'une fabrique de session et d'un modèle JDBC protégés par des threads initialisé au démarrage. Un appel simultané n'est donc pas un problème: il est thread-safe.
Il n'y a aucune raison pour qu'un référentiel soit un prototype. L’injection d’un prototype DAO dans un service singleton entraîne toujours l’appel simultané de chaque prototype.
Il n'y a aucune raison de le faire.
Pas de problème: il devrait être thread-safe s'il est codé correctement.
Les composants annotés avec @Repository doivent être singleton, car ils n'auront jamais plusieurs états/différents au cours de leur vie. Oui, le seul état qu'il peut contenir est l'objet de connexion, qui ne sera défini qu'une seule fois lors de la création de l'objet. Et il contiendra la logique/les méthodes pour communiquer avec le magasin de données et chaque méthode prendra/retournera les objets de données requis. Il n'est donc pas nécessaire d'avoir plusieurs instances de référentiel.
Spring ne gère pas les problèmes de concurrence pour vous. Cela ne voulait pas. Tout ce que cela fait est de vous permettre de contrôler le nombre d'instances créées afin que votre application puisse fonctionner correctement.
Singleton scope (comme évident) créera une seule instance du bean donné et le transmettra à tous les objets dépendants.
La portée du prototype de chaque objet dépendant créera sa propre instance, non partagée entre d'autres objets.
Pour les objets DAO, il est très peu probable que vous ayez besoin de plusieurs instances pour communiquer avec la base de données. Donc, singleton est utilisé presque toujours.