I have been working with Spring Data JPA repository in my project for some time and I know the below points:
In the repository interfaces, we can add the methods like findByCustomerNameAndPhone() (assuming customerName and phone are fields in the domain object).
Then, Spring provides the implementation by implementing the above repository interface methods at runtime (during the application run).
I am interested on how this has been coded and I have looked at the Spring JPA source code & APIs, but I could not find answers to the questions below:
How is the repository implementation class generated at runtime & methods being implemented and injected?
Does Spring Data JPA use CGlib or any bytecode manipulation libraries to implement the methods and inject dynamically?
Could you please help with the above queries and also provide any supported documentation ?
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, see JpaQueryLookupStrategy. The parsing logic for the query derivation can be found in PartTree. The store specific translation into an actual query can be seen e.g. in JpaQueryCreator.
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.
Related
Not sure if this will be considered a "legitimate question" or "purely opinion based", but is there a "best practice" with regards to directly testing a repository in a Spring Boot application? Or, should any integration testing simply target the associated service?
The reasoning for the question is simply the fact that, for the most part, a repository in a Spring Boot application contains no project-generated code. At best, it contains project-defined method signatures which Spring generates implementations for (assuming correct naming conventions).
Thanks...
If you can mess it up, you should test it. Here the opportunities to mess up can include:
Custom Queries (using #Query) might be wrong (there can be all kinds of logic mistakes or typos writing a query with no compile-time checking)
Repository methods where the query is derived from the method name might not be what you intended.
Arguments passed in, the type on the parameter list might not match the type needed in the query (nothing enforces this at compile time).
In all these cases you're not testing Spring Data JPA, you're testing the functionality you are implementing using Spring Data JPA.
Cases of using provided methods out of the box, like findOne, findAll, save, etc., where your fingerprints are not on it, don't need testing.
It's easy to test this stuff, and better to find the bugs earlier than later.
Yes, I think is a good pratice to do that. You could use #DataJpaTest annotation, it starts a in memory database. The official documentation says:
You can use the #DataJpaTest annotation to test JPA applications. By default, it configures an in-memory embedded database, scans for #Entity classes, and configures Spring Data JPA repositories. Regular #Component beans are not loaded into the ApplicationContext.
Link to the docs: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html
Starting from the idea that repositories should be used only inside services and services are used to interact with the other layers of the system, I would say that testing services should be enough in the majority of cases.
I would not test standard repository methods like findAll, or findBy.., they were tested already and the purpose is not to test JPA, but rather the application.
The only repository methods that should have direct tests are the ones with custom queries. These queries may be located in a shared library and it is not efficient to write similar tests across different projects(in this case regression is a big concern)
I started to read this tutorial: spring boot tutorial
In this I read that under model module they implemented POJOs and Repository interfaces. -> tutorial on github
In Repository interfaces I found two methods without implementations:
findByUsername,
findByAccountUsername.
My questions are:
How does it work when those methods in repository interfaces have no
implementations and those are not inherited from any super class?
Does it work with name conventions and reflections?
Does Spring Data has inmemory database to work with?
(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?
For your question 1 and 2, they are right. They use naming convention and reflection. If you don't want to use their naming convention, you can use #Query with HQL, and certainly the hidden class (which implements for your interface) will handle these query also (you don't need to roll the implementation out).
For your last question, as list of IMDB here: https://en.wikipedia.org/wiki/List_of_in-memory_databases , spring data is not supporting for them. You must invoke another Java driver or spring product for each one.
I have just started learning Java Spring and the concept of Dependency Injection (DI) and Inversion of Control (IoC).
I learned that all objects whether it is singleton, prototype or request and sessions, are all retrieved from the container.
The container manages the dependencies between classes and the lifecycle/scope of the object.
The fundamental idea behind this is there are no "new" operators for application using Spring Framework as the backbone of the system. (Please correct me if I am wrong).
I wanted to modernize legacy applications coded without the Spring framework and manages the 3rd party libraries classes and injects them using Spring.
How should I approach this?
I learned that all objects whether it is singleton, prototype or request and sessions, are all retrieved from the container.
That is not quite right. Not all objects, but those you have the cotainer told to resolve, are retrieved from the container. In general you use the #Component annotation to mark which of your objects should the container know of. Besides #Component there are other annotations which do in principle the same, but allow a more finegrained semantics, e.g. #Repository annotation, which is at its base #Component and put #Target, #Retention, #Documented on top.
The container manages the dependencies between classes and the lifecycle/scope of the object.
Yes. The container does the wiring up for you, i.e. resolving dependencies annotated with #Ressource, #Autowired or #Inject depending on which annotation you prefer.
During the lifecycle there are possible events, which allow usage of lifecycle callbacks.
Also: You could determine the bean scope.
The fundamental idea behind this is there are no "new" operators for application using Spring Framework as the backbone of the system. (Please correct me if I am wrong).
The fundamental principle is, that you delegate the creation of objects of a certain kind to the container. Separation of creation and consumption of objects allows greater flexibility and in consequence better testability of your application.
Besides the "components" of your application, there are e.g. the typical containers like ArrayList or HashMap, upon which you use the new-operator as before.
I wanted to modernize legacy applications coded without the Spring framework and manages the 3rd party libraries classes and injects them using Spring.
How should I approach this?
From what was said above, it should be "simple":
1) Go through each class file and look for its dependencies
2) Refactor those out and put #Component on top of the class
Special case: 3rd party objects, where you do not have access to the source. Then you have to wrap its construction yourself into a factory e.g. with #Bean.
3) Add the missing dependencies via #Autowired (the spring specific annotation for marking dependencies)
4) Refactor components of the service layer with #Service annotationinstead of #Component.
5) Refactor the data access layer, instead of using #Component, you can use #Repository.
This should give you a base to work with.
Extending spring based interfaces is discouraged as it unnecessarily couples the code with Spring. Does the same reasoning applies to annotations as well? We need to have them imported in the source code before using them.
I'll take the opposite viewpoint--of course using a Spring-specific annotation ties the class to Spring. I claim it's self-evident that importing and using Spring annotations ties the code to Spring (although you could trivially redefine those annotations for a non-Spring environment). The key for me is how deeply it's tied to Spring.
It's easier to check for, and process, annotations, than it is to restructure a class hierarchy or duplicate the functionality of a non-marker interface. Assuming you wanted to leave the annotations in, and could duplicate the logic behind the annotations, it'll be easier to do that (IMO) than to recreate whatever class/interface hierarchy implemented similar functionality.
The other key is the word "unnecessarily". I have yet to create a Spring application and need those classes outside of a Spring environment. When I have (generally for exposed APIs) it's been at the interface level. Note, however, that I knew from the onset that this exposure would exist and I planned accordingly.
Most would argue that this does not. While you've imported those annotations needed to ensure that Spring handles the request or wraps the transactions, you are not extending or implementing a specific class or interface.
Think about it this way, when you've annotated that class you're telling Spring to do various things based upon your configuration. Take out those annotations, and what you have is a POJO which just has some methods. It's a completely valid object without those annotations, it might not do what you wish it do (i.e. handle requests), but the code is still performing the same logic as it was with the annotations -- you are just now responsible for calling it appropriately.
I have a question on DDD & Spring. I always design my application around anemic domain model and service taking care of business logic/persistence.
Assume you have a spring managed persistence/respository service for a Domain object e.g. Book. If I have to expose a save() method on book then i will need repository bean inside my domain or i will have to look up the context for the repository bean. Which is exactly opposite of Dependency Injection.
Now, If I have repository id injected into domain and domain object is cached ( clustered cache) and then on deserialization it will not have the injected repository service as spring containers will be different.
I might be wrong but if someone can explain me how this scenario will work, it would be of great help
I think that the "facade" of your application should use a Repository (or other infrastructure service) to save the "book". The book should not save it-self, this is responsibility of the Repository.
If you need to make any infrastructure operation (for example, search the database) from a Domain Entity, then you should gain access to this Repository by looking up the context (and getting coupled to Spring as a result) or injecting the Repository through Dependency Injection in the Entity.
The problem is that the "instantiation" of the Entity is not responsibility of Spring but of the Persistence Provider, so Spring cannot handle this injection. What to do?
Well, there are several ways (none of them very "beautyful") to do this:
Through AOP: you can instrument the code with Aspect Oriented Framework (like AspectJ) configuring the system to inject whatever dependency in the Entity in the instantiation moment.
Through a Hibernate interceptor: if your Persistence Provider is Hibernate, it offers you a hook to place interceptors in certain points of the life cycle of the Entities. You can configure an interceptor that looks-up the spring context to inject dependencies in the instantiation of every Entity.
Maybe the easiest way is to implement a little and static "serviceLocator" coupled with spring that looks-up services asked by the Entities when they need them. This service locator is just a layer to avoid your entities to get coupled to Spring.
I think that a "save" method (save in a DB, in example) doesn't belong to the domain object... Does the book "save" itself? Or is the repository saving it?...