En primer lugar, no hay generación de código, lo que significa: no hay CGLib, no hay generación de código de bytes en absoluto. El enfoque fundamental es que una instancia de proxy JDK se crea mediante programación utilizando la ProxyFactory
API de Spring para respaldar la interfaz e MethodInterceptor
intercepta todas las llamadas a la instancia y enruta el método a los lugares apropiados:
- Si el repositorio se ha inicializado con una parte de implementación personalizada (consulte esa parte de la documentación de referencia para obtener más detalles) y el método invocado se implementa en esa clase, la llamada se enruta allí.
- Si el método es un método de consulta (vea
DefaultRepositoryInformation
cómo se determina), el mecanismo de ejecución de consultas específico de la tienda se activa y ejecuta la consulta que se determina que se ejecutará para ese método al inicio. Para eso, existe un mecanismo de resolución que intenta identificar consultas declaradas explícitamente en varios lugares (utilizando @Query
en el método, consultas con nombre JPA) eventualmente recurriendo a la derivación de consultas a partir del nombre del método. Para la detección del mecanismo de consulta, consulte JpaQueryLookupStrategy
. La lógica de análisis para la derivación de consultas se puede encontrar en PartTree
. La traducción específica de la tienda en una consulta real se puede ver, por ejemplo, en JpaQueryCreator
.
- Si nada de lo anterior se aplica, el método ejecutado debe ser uno implementado por una clase base de repositorio específica de la tienda (
SimpleJpaRepository
en el caso de JPA) y la llamada se enruta a una instancia de eso.
El interceptor de métodos que implementa esa lógica de enrutamiento es QueryExecutorMethodInterceptor
, la lógica de enrutamiento de alto nivel se puede encontrar aquí .
La creación de esos proxies está encapsulada en una implementación estándar de patrón de fábrica basada en Java. La creación de proxy de alto nivel se puede encontrar en RepositoryFactorySupport
. Las implementaciones específicas de la tienda luego agregan los componentes de infraestructura necesarios para que para JPA pueda seguir adelante y simplemente escribir código como este:
EntityManager em = … // obtain an EntityManager
JpaRepositoryFactory factory = new JpaRepositoryFactory(em);
UserRepository repository = factory.getRepository(UserRepository.class);
La razón por la que lo menciono explícitamente es que debería quedar claro que, en su esencia, nada de ese código requiere que se ejecute un contenedor Spring en primer lugar. Necesita Spring como una biblioteca en la ruta de clases (porque preferimos no reinventar la rueda), pero es independiente de los contenedores en general.
Para facilitar la integración con los contenedores DI, por supuesto, hemos construido la integración con la configuración de Spring Java, un espacio de nombres XML, pero también una extensión CDI , de modo que Spring Data se pueda usar en escenarios CDI simples.
@Repository
interfaces anotadas en primer lugar? AlRepositoryFactorySupport#getRepository()
observar, se muestra que toma la clase de interfaz como parámetro, por lo que debe descubrirse en otro lugar. En particular, estoy tratando de averiguar cómo encontrar una interfaz anotada y generar automáticamente un bean proxy JDK que implemente la interfaz, muy parecido a Spring-Data, pero para un propósito específico de la aplicación no relacionado con los repositorios.RepositoryComponentProvider
. No suceden cosas automáticas, sino un escaneo de componentes para ciertos tipos (ya sea con anotaciones o con una anotación) y unaFactoryBean
configuración para cada uno de ellos.