我在项目中使用Spring Data JPA仓库已有一段时间了,我知道以下几点:
在存储库界面中,我们可以添加类似findByCustomerNameAndPhone()
的方法(假设customerName
和phone
是域对象中的字段)。
然后,Spring通过在运行时(在应用程序运行期间)实现上述存储库接口方法来提供实现。
我对它的编码方式很感兴趣,并查看了Spring JPA源代码和API,但是找不到以下问题的答案:
如何在运行时生成存储库实现类以及如何实现和注入方法?
Spring Data JPA是否使用CGlib或任何字节码操作库来实现方法并动态注入?
您能否为上述查询提供帮助,并提供任何受支持的文档?
最佳答案
首先,没有代码生成正在进行,这意味着:没有CGLib,根本没有字节代码生成。基本方法是使用Spring的ProxyFactory
API以编程方式创建JDK代理实例以支持接口,而MethodInterceptor
拦截对实例的所有调用并将该方法路由到适当的位置:
如果存储库已使用自定义实现部件进行了初始化(有关详细信息,请参见that part of the reference documentation),并且所调用的方法在该类中实现,则将调用路由到那里。
如果该方法是查询方法(有关如何确定的信息,请参见DefaultRepositoryInformation
),那么商店特定的查询执行机制将启动并执行在启动时针对该方法确定要执行的查询。为此,采用了一种解析机制,该机制尝试在各个位置标识显式声明的查询(使用方法上的@Query
,使用JPA命名查询),最终退回到从方法名进行查询的派生。有关查询机制的检测,请参见JpaQueryLookupStrategy
。查询派生的解析逻辑可以在PartTree
中找到。例如,可以看到将商店特定的翻译成实际查询。在JpaQueryCreator
中。
如果以上方法均不适用,则所执行的方法必须由商店特定的存储库基类(在JPA的情况下为SimpleJpaRepository
)实现,并且该调用将路由到该实例的实例中。
实现路由逻辑为QueryExecutorMethodInterceptor
的方法拦截器,可以找到here的高级路由逻辑。
这些代理的创建被封装到基于Java的标准Factory模式实现中。可以在RepositoryFactorySupport
中找到高级代理创建。然后,特定于商店的实现将添加必要的基础结构组件,以便对于JPA而言,您可以继续编写以下代码:
EntityManager em = … // obtain an EntityManager
JpaRepositoryFactory factory = new JpaRepositoryFactory(em);
UserRepository repository = factory.getRepository(UserRepository.class);
我明确提到的原因是,应该清楚的是,从根本上讲,该代码中的任何内容都不需要Spring容器来运行。它需要Spring作为类路径上的库(因为我们不想重塑轮子),但是通常与容器无关。
为了简化与DI容器的集成,我们当然要与Spring Java配置,XML名称空间以及CDI extension建立集成,以便可以在普通CDI场景中使用Spring Data。