How are Spring Data repositories actually implemented?
First of all, there's no code generation going on, which means: no CGLib, no byte-code generation at all. The fundamental approach is that a JDK proxy instance is created programmatically using Spring's ProxyFactory
API to back the interface and a MethodInterceptor
intercepts all calls to the instance and routes the method into the appropriate places:
- If the repository has been initialized with a custom implementation part (see that part of the reference documentation for details), and the method invoked is implemented in that class, the call is routed there.
- If the method is a query method (see
DefaultRepositoryInformation
for how that is determined), the store specific query execution mechanism kicks in and executes the query determined to be executed for that method at startup. For that a resolution mechanism is in place that tries to identify explicitly declared queries in various places (using@Query
on the method, JPA named queries) eventually falling back to query derivation from the method name. For the query mechanism detection, seeJpaQueryLookupStrategy
. The parsing logic for the query derivation can be found inPartTree
. The store specific translation into an actual query can be seen e.g. inJpaQueryCreator
. - If none of the above apply the method executed has to be one implemented by a store-specific repository base class (
SimpleJpaRepository
in case of JPA) and the call is routed into an instance of that.
The method interceptor implementing that routing logic is QueryExecutorMethodInterceptor
, the high level routing logic can be found here.
The creation of those proxies is encapsulated into a standard Java based Factory pattern implementation. The high-level proxy creation can be found in RepositoryFactorySupport
. The store-specific implementations then add the necessary infrastructure components so that for JPA you can go ahead and just write code like this:
EntityManager em = … // obtain an EntityManager
JpaRepositoryFactory factory = new JpaRepositoryFactory(em);
UserRepository repository = factory.getRepository(UserRepository.class);
The reason I mention that explicitly is that it should become clear that, in its core, nothing of that code requires a Spring container to run in the first place. It needs Spring as a library on the classpath (because we prefer to not reinvent the wheel), but is container agnostic in general.
To ease the integration with DI containers we've of course then built integration with Spring Java configuration, an XML namespace, but also a CDI extension, so that Spring Data can be used in plain CDI scenarios.
how annotation @Repository in java spring work?
Spring Repository is responsible for importing the DAO's into the DI container and also it makes the unchecked exceptions into Spring DataAccessException
. The Spring Repository annotation is meta annotated with the @Component annotation so that the repository classes will be taken up for component scanning.
Teams implementing traditional Java EE patterns such as "Data Access
Object" may also apply this stereotype to DAO classes, though care
should be taken to understand the distinction between Data Access
Object and DDD-style repositories before doing so. This annotation is
a general-purpose stereotype and individual teams may narrow their
semantics and use as appropriate.A class thus annotated is eligible for Spring
DataAccessException
translation when used in conjunction with a
PersistenceExceptionTranslationPostProcessor
. The annotated class is
also clarified as to its role in the overall application architecture
for the purpose of tooling, aspects, etc.Source: JavaDoc
but in your case you are also extending the JpaRepository
of Spring Data JPA. Spring Data automatically provides implementations of common CRUD operations. The JpaRepository
extends the interface CrudRepository
which has the methods declared for all basic crud operations.
public interface EquipmentRepository extends JpaRepository<Account, Long> { … }
Defining this interface serves two purposes:
- First, by extending
JpaRepository
we get a bunch of generic CRUD
methods into our type that allows saving Equipments, deleting them and
so on. - Second, this will allow the Spring Data JPA repository infrastructure
to scan the classpath for this interface and create a Spring bean for
it.
The @EnableJpaRepositories
scans all packages below com.acme.repositories
for interfaces extending JpaRepository
and creates a Spring bean for it that is backed by an implementation of SimpleJpaRepository
(spring data provides default imlpementations of CRUD repository through this class).
So that is why even when you haven't defined the method , you are able to do crud operations through this setup.
Refer : https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.repositories
How spring picks up the implementation for interface at run time
What @sairamch04 said is alright. I can only add, that when query is defined via @Query
annotation or using standard jpa method name, a proxy object is created to execute the query. The creation of these proxies is within factory objects, such as JpaRepositoryFactory
mentioned. Otherwise it falls back to implementation such as SimpleJpaRepository
. For more information about repository, you can call RepositoryFactorySupport.getReporitory()
method in spring-data-commons.
How are the methods: findAll(), save() etc implemented in spring-data?
There's no way to answer your question with just the information you've provided. That's not a bad thing. That's a very good thing. That's the power of interfaces and of Spring's most basic ability, dependency injection. The whole idea behind both of those concepts is that your code, and maybe even the programmer, doesn't know anything about the implementation of a particular interface. There can be a few or 100s of unique implementations of that interface, and each one of those means at least a slightly different answer to your question.
Another way to "answer" your question is to say "The implementation of the interface you're interacting with in your code is defined by whichever concrete implementation of that interface you've configured to actually perform that role.".
In the case of Spring Boot, the answer to your question is often defined by your application's package dependencies, usually defined via a Maven or Gradle project file. Here, for example, are the lines you'd add to a Gradle project definition to cause Spring Boot to implement your CRUD operations using JPA and MySQL:
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile("mysql:mysql-connector-java:5.1.13")
If you have a working app, then the answer to your question is probably determined by lines similar to these in your Maven or Gradle file or in the equivalent definition of your project per whatever method you are using to define it. If you don't have a working app, then maybe you haven't yet even chosen a backing implementation, and your question literally has no answer.
If you want a more definitive answer, why don't you post more details about your app, like the code, and more importantly, your Maven or Gradel project file.
Spring Data JPA underlying mechanism without implementation
(1) How does it work when those methods in repository interfaces have
no implementations and those are not inherited from any super class?
The Repository interfaces are being implemented (backed up) by Spring Container at Runtime.
(2) Does it work with name conventions and reflections?
Yes, it works on naming conventions and spring container uses JDK's proxy classes to intercept the calls to the Repository.
(3) Does Spring Data has inmemory database to work with?
No, Spring does not use any inmemory database
Please refer the below link for more detailed explanation:
How are Spring Data repositories actually implemented?
Spring JPA custom repository implementation does not work
I'm going to answer my own question after my investigation.
It is not obvious (at least not to me) in Spring's documentation here that the CustomRepository/Impl
mechanism must only be used for a single repository. If you want to create some custom implementation to be inherited by multiple repositories, you'll have to customize the base repository, which is going to be used to back all repository beans.
So I ended up adding an int myTestMethod(OffsetDateTime threshold)
implementation to the base repository impl BaseRepositoryImpl
. This method will be used to back the method declared in MyEntityDataRepository
which extends TestRepository
. Note: you must let your repository to extend the interface that declares the custom method. Otherwise, the function in the base repository impl will not be available to the repository bean which is a proxy for the interfaces only, not the base repository impl.
Also, you can actually override the base repository's implementation if you customize the same method in the entity repository.
This is not ideal, but it works. I'd hope I can restrict the custom method availability to some repositories only. One way to do that is to split the different "groups" of repositories into separate disjoint packages and declare a distinct base-class
for each separate search path. But that may not make sense in many cases.
What implementation will be used for PagingAndSortingRepository in runtime?
The implementation for the methods declared in the PagingAndSortingRepository
are defined in SimpleJpaRepository
.
If all what you want to do within a transaction is handled by a single repository call you don't need any extra @Transactional
, but typically you do want the transaction to cover more then one call or at least a load operation and the manipulation of an entity afterwards. In those cases you would typically use a method annotated with @Transactional
. But you could also use for example a TranactionTemplate
which can be nice for example in certain kind of tests.
Quarkus extension for spring data API - automatic repository implementation generation
Answering to my own question.
I have opened an issue in github. And it turns out that @RepositoryDefinition isn't supported at the moment. But there is a good chance that it will be supported soon. You can follow the issue here.
Related Topics
Java "Void" and "Non Void" Constructor
How to Maintain Jtable Cell Rendering After Cell Edit
What's the Difference Between Concurrenthashmap and Collections.Synchronizedmap(Map)
Compiling a Java Program into an Executable
How to Load a Jar File at Runtime
Are Static Fields Open for Garbage Collection
Why Must Local Variables, Including Primitives, Always Be Initialized in Java
How to Parse a Mathematical Expression Given as a String and Return a Number
How Will Java Lambda Functions Be Compiled
Calling a Subclass Method from Superclass
Java and Gui - Where Do Actionlisteners Belong According to MVC Pattern
Java Comparison with == of Two Strings Is False
When and How to Use a Threadlocal Variable
Java 8 Iterable.Foreach() VS Foreach Loop