Spring Data 1# - how repositories work under the hood

Spring Data repositories enable programmers to manage entities in more advanced and convenient way than with plain EntityManager. It is interesting how repositories are working behind the scenes. There is very little to be done on the developer side comparing to what is happening under the hood.


Quick reminder on Spring Data repositories

Spring Data repositories can significantly reduce the amount of boilerplate code used for data access purposes and manage entities in more complex wayThe main interface - Repository is extended by CrudRepository which provides methods used to perform CRUD (Create Read Update Delete) operations on entities. Lets have a brief look at some of the core Spring Data and JPA repositories features:
  1. Already existing repositories enable us to perform basic CRUD and query operations.
  2. It is possible to define queries just by using proper repository method names.
  3. Annotations are widely used in repositories to configure data access layer - writing custom queries in JPQL, adding query hints, setting locks, configuring transactions. 
  4. Support for paging.
  5. Support for web projects and Spring MVC.
We will concentrate on how Spring Data and JPA manages to deliver some of those functionalities - we will look under the hood of repositories implementation.

Under the hood - SimpleJpaRepository

To analize what is happening under the hood we will use a simple example of repository that extends CrudRepository:


Since repositories are interfaces, that means Spring has to implement them behind the scenes before we can use them. The Spring Data repository implementation (when we use JPA) is SimpleJpaRepository. It is used for both CrudRepository nad JpaRepository. As it is written in the documentationSimpleJpaRepository gives more complex interface than plain EntityManager Full documentation can be found here - SimpleJpaRepository. There are multiple methods to query entities aswell as methods to save the entity, flush the changes and many others. 

Repository Proxy

During runtime we can verify the actual implementation of our clientRepository when we use that in one of our services:




The clientRepository is actually a JdkDynamicAopProxy. What does it mean? Why it is not a SimpleJpaRepository? Spring uses proxies in multiple places when it is needed to intercept target object methods calls and perform additional operations. The target object (SimpleJpaRepository) is just wrapped by a proxy object. Lets have a look at a picture below, to understand more how does JdkDynamicAopProxy work in this case:





The picture presents how JdkDynamicAopProxy works in the context of our ClientRepository which extends CrudRepository. Proxy object is implementing the same interface as the target SimpleJpaRepository. It makes it possible for a proxy to intercept all the calls made to our ClientRepository. MethodInterceptor intercepts the calls and performs any additional operations if it is needed. That is bascially a simple explanation how aspect oriented approach is implemented in Spring. As you can see, it is also used in Spring Data repositories. All of the MethodInterceptor additional logic is added at runtime since JdkDynamicAopProxy is created at runtime. Ok, so what are the additional operations that are added by JdkDynamicAopProxy in the MethodInterceptor? Is call to SimpleJpaRepository always made? The answer is - it depends:
  1. If the call is being made to query method with @Query annotation or to a method with name that will be used to construct query, then MethodInterceptor calls special Spring Data infrastructre services which are used to construct a query based on the @Query JPQL statement or based on the method name. This mechanism is decoupled from SimpleJpaRepository which means that SimpleJpaRepository will not be called (it would not be even possible - SimpleJpaRepository can not contain implementation of methods declared at compile time in ClientRepository...).
  2. If it is a method implemented in SimpleJpaRepository or method implemented in some custom class that extends SimpleJpaRepository then a call will be routed directly to the target repository object.
So, our findByName method defined in ClientRepository defines the query based on the method name itself. It means that under the hood, during method call, JdkDynamicAopProxy will itercept it and invoke other methods from Spring Data classes to build and execute a proper query based on the method name. However, when we call some method that is being inherited from CrudRepository, then JdkDynamicAopProxy will call SimpleJpaRepository since it implements CrudRepository methods.

Dynamic query creation

We have said that MethodInterceptor calls special 'Spring Data infrastructure classes' to create and invoke a query based on @Query annotation content or repository method name. How it works exacly? 
To build a query based on the method name, query creation mechanism does the following things:
  1. Looks for the following prefixes in the method name: find...By, read...By, query...By, count...By, and get...By.
  2. If the prefix is found, then:
    1. The content after prefix will be used to construct the 'where' clause of the query. For example findByNameAndAge wille enable us to query data based on two columns - name and age. As you can see, we can chain the query parameters using 'And'  and 'Or' keywords. Query parameters values are passed through method parameters.
    2. The content inside prefix will be used for additional query keywords. For example findDistinctBy prefix will provide Distinct keyword to the query
Below is the example for repository method where query will be generated based on method's name:

More details regarding query creation from method name can be found in the Spring Data documentation: Spring Data docs.

@Query annotation is supported by the JPA module and it lets us define query as string using JPQL language. You can have a look at the simple example below:


Is is usually preferred to use JPQL when query becomes to complicated to define just by method name. You can find more details on the @Query mechanism here: Spring Data JPA docs.

Conclusions

To sum up:
  1. The actual implementation of Spring Data repositories like CrudRepository or JpaRepository is SimpleJpaRepository which provides implementation for more complex interface than plain EntityManager.
  2. JdkDynamicAopProxy is used at runtime as a SimpleJpaRepository proxy. It intercepts all repository method calls and routes them to a target object (SimpleJpaRepository) or invokes other Spring Data infrastructure services to handle query creation based on the @Query annotation or method name. 

Komentarze

Popularne posty z tego bloga

Hibernate 1# - entity states overview

Data consistency and performance in web applciation