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 d'octet du tout. L'approche fondamentale est qu'une instance de proxy JDK est créée par programme à l'aide de l' ProxyFactory
API de Spring pour sauvegarder l'interface et MethodInterceptor
intercepte tous les appels à l'instance et achemine la méthode aux endroits appropriés:
- 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é.
- Si la méthode est une méthode de requête (voir
DefaultRepositoryInformation
comment cela est déterminé), le mécanisme d'exécution de requête spécifique au magasin entre en action et exécute la requête déterminée à être exécutée pour cette méthode au démarrage. Pour cela, un mécanisme de résolution est en place qui tente d'identifier les requêtes explicitement déclarées à divers endroits (en utilisant @Query
sur la méthode, les requêtes nommées JPA) en retombant finalement vers 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 pour la dérivation de la requête se trouve dans PartTree
. La traduction spécifique au magasin en une requête réelle peut être vue par exemple dans JpaQueryCreator
.
- Si aucune des solutions ci-dessus ne s'applique, la méthode exécutée doit être 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é vers une instance de celle-ci.
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 proxies est encapsulée dans une implémentation de modèle Factory standard basée sur Java. La création de proxy de haut niveau se trouve dans RepositoryFactorySupport
. Les implémentations spécifiques au magasin ajoutent ensuite les composants d'infrastructure nécessaires afin que pour JPA, vous puissiez continuer et écrire simplement du code comme celui-ci:
EntityManager em = … // obtain an EntityManager
JpaRepositoryFactory factory = new JpaRepositoryFactory(em);
UserRepository repository = factory.getRepository(UserRepository.class);
La raison pour laquelle je mentionne cela explicitement est qu'il devrait devenir clair que, dans son cœur, rien de ce code ne nécessite un conteneur Spring pour s'exécuter en premier lieu. Il a besoin de Spring comme bibliothèque sur le chemin de classe (car nous préférons ne pas réinventer la roue), mais est indépendant du conteneur en général.
Pour faciliter l'intégration avec les conteneurs DI, nous avons bien sûr ensuite construit une intégration avec la configuration Spring Java, un espace de noms XML, mais aussi une extension CDI , afin que Spring Data puisse être utilisé dans des scénarios CDI simples.
@Repository
interfaces annotées en premier lieu? En regardantRepositoryFactorySupport#getRepository()
montrer qu'elle prend la classe d'interface comme paramètre, elle doit donc être découverte ailleurs. J'essaie en particulier de comprendre comment trouver une interface annotée et générer automatiquement un bean proxy JDK qui implémente l'interface, un peu comme spring-data, mais dans un but spécifique à l'application non lié aux référentiels.RepositoryComponentProvider
. Il n'y a pas de choses automatiques qui se passent mais une analyse des composants pour certains types (annotés ou porteurs d'une annotation) et uneFactoryBean
configuration pour chacun d'entre eux.