web-dev-qa-db-fra.com

Comment les référentiels Spring Data sont-ils réellement mis en œuvre?

Je travaille avec le référentiel Spring Data JPA dans mon projet depuis un certain temps et je connais les points ci-dessous:

  • Dans les interfaces de référentiel, nous pouvons ajouter les méthodes telles que findByCustomerNameAndPhone() (en supposant que customerName et phone sont des champs dans l'objet de domaine).
  • Ensuite, Spring fournit l'implémentation en implémentant les méthodes d'interface de référentiel ci-dessus lors de l'exécution (pendant l'exécution de l'application).

Je suis intéressé par la façon dont cela a été codé et j'ai examiné le code source et les API Spring JPA, mais je n'ai pas pu trouver de réponses aux questions ci-dessous:

  1. Comment la classe d'implémentation du référentiel est-elle générée au moment de l'exécution et les méthodes sont-elles implémentées et injectées?
  2. Spring Data JPA utilise-t-il CGlib ou des bibliothèques de manipulation de code-octet pour implémenter les méthodes et injecter de manière dynamique?

Pourriez-vous s'il vous plaît aider avec les requêtes ci-dessus et également fournir toute documentation prise en charge?

87
developer

Tout d'abord, il n'y a pas de génération de code en cours, ce qui signifie: pas de CGLib, pas de génération de code octet du tout. L'approche fondamentale est qu'une instance de proxy JDK soit créée par programme à l'aide de l'API ProxyFactory de Spring pour sauvegarder l'interface et qu'un MethodInterceptor intercepte tous les appels de l'instance et achemine la méthode aux emplacements appropriés:

  1. Si le référentiel a été initialisé avec une partie d'implémentation personnalisée (voir cette partie de la documentation de référence pour plus de détails), et que la méthode appelée est implémentée dans cette classe, l'appel y est acheminé.
  2. Si la méthode est une méthode de requête (voir DefaultRepositoryInformation pour savoir comment cela est déterminé), le mécanisme d'exécution de la requête spécifique au magasin déclenche et exécute la requête dont l'exécution a été déterminée pour cette méthode au démarrage . Pour cela, un mécanisme de résolution est en place qui essaie d’identifier les requêtes explicitement déclarées à divers endroits (en utilisant @Query sur la méthode, les requêtes nommées JPA) ont finalement recours à la dérivation de requête à partir du nom de la méthode. Pour la détection du mécanisme de requête, voir JpaQueryLookupStrategy . La logique d'analyse de la dérivation de la requête se trouve dans PartTree . La traduction spécifique du magasin dans une requête réelle peut être vue, par exemple. dans JpaQueryCreator .
  3. Si aucun des cas ci-dessus ne s'applique, la méthode exécutée doit être celle implémentée par une classe de base de référentiel spécifique au magasin ( SimpleJpaRepository dans le cas de JPA) et l'appel est acheminé dans une instance de cette.

L'intercepteur de méthode implémentant cette logique de routage est QueryExecutorMethodInterceptor, la logique de routage de haut niveau peut être trouvée ici .

La création de ces mandataires est encapsulée dans une implémentation de modèle Factory standard Java. La création de proxy de haut niveau peut être trouvée dans RepositoryFactorySupport . Les implémentations spécifiques à chaque magasin ajoutent ensuite les composants d'infrastructure nécessaires afin que, pour JPA, vous puissiez continuer et écrire simplement le code suivant:

EntityManager em = … // obtain an EntityManager
JpaRepositoryFactory factory = new JpaRepositoryFactory(em);
UserRepository repository = factory.getRepository(UserRepository.class);

La raison pour laquelle je le mentionne explicitement est qu'il devrait être clair que, dans son essence, rien de ce code n'exige qu'un conteneur Spring soit exécuté en premier lieu. Il a besoin de Spring en tant que bibliothèque sur le classpath (car nous préférons ne pas réinventer la roue), mais est agnostique au conteneur en général.

Pour faciliter l’intégration avec les conteneurs DI, nous avons bien sûr ensuite construit l’intégration avec Spring Java, un espace de noms XML, mais aussi une extension CDI , afin que Spring Data peut être utilisé dans des scénarios CDI simples.

113
Oliver Drotbohm