How to use multiple spring-boot-starter-data-* dependencies - spring-boot

Taking an example: I want some entities to be persisted in MongoDB and some in Cassandra.
I have my repository interfaces extending CrudRepository. My Cassandra entities have #Table and my MongoDb entities have #Document annotations.
However, on startup, spring-data attempts to create an instance of a MyMongoObjectRepository, and thus complains that "Cassandra entities must have the #Table, #Persistent or #PrimaryKeyClass Annotation".
How are the libraries discovering which repository interfaces they are supposed to implement, and how can I control them so they don't try to implement them for unsupported entities?
Further question: if I wanted to store some entities in both storage systems, can multiple implementations of a single repository be generated, or do I need an interface for each store?
Edit
On further inspection, the problem seems to be from the entity scanning rather than the repository scanning. Both mappers pick up all the entities (as their annotations all extend #Persistent). One of the Mongo entities has a nested entity (without any annotations) that the Cassandra mapper cannot deal with.

You can use a basePackages setting in #EnableMongoRepositories and #EnableJpaRepositories to specify where they should look for repository definitions.
Like so:
#EnableMongoRepositories(basePackages={
"com.some.package.to.look.inside",
"com.some.package.to.look.also.at"
})
And
#EnableJpaRepositories(basePackages={
"com.some.differentpackage.to.look.inside",
"com.some.differentpackage.to.look.also.at"
})
For this to work you need to namespace your repository definitions in sensible packages.
Answer to your follow up question:
If you wanted to store entities multiple places at once I would implement a service in front of the repositories making use of #Autowire to dependency inject the repositories and setting a #Transactional on the service method which calls repository methods. Having #Transactional on the service method ensures that if an error would occur while saving it will ensure that no half-way saves are left laying around, even doing rollbacks if necessary.
Edit:
#Transactional does not work for db's that do not support transactions like Cassandra and MongoDB.

Problem is that all the different entity scanners use #Persistent as an annotation they're looking for, while all the repo-specific annotations (#Table, #Document, etc.) also have #Persistent as a meta-annotation.
Therefore, the entities for the different repositories must be in separate packages, and you must construct your own scanner in order to pass the packages to it, as it doesn't not accept a generic filter.

Related

Adding new DB support in spring data

Currently spring data has multiple db support (mysql, cassandra, mongo.. very big list), however i want to add my custom repository from the scratch like adding custom db support in spring data. I don't want to extend any existing repositories, instead I want to create a parallel repository strutcutre for my custom datasource. Looking at current implementation it looks like tedious task. It would be a great if someone could help me with minimal requirement to do this.
You could create a repository annotated bean where you would inject EntityManager or the proper bean that is acting like that, depending on database type that you are using.
#Repository
public class MyCustomRepositoryImpl implements MyCustomRepository {
#Autowired
private EntityManager entityManager;
//the methods that you are going to create.
}
For more details see:
https://docs.spring.io/spring-data/data-commons/docs/1.6.1.RELEASE/reference/html/repositories.html
Chapter: 1.3 Custom implementations for Spring Data repositories

Where to use #Transactional annotation and #Repository annotation

Some of the examples on internet use #Transactional annotation on DAO implementation methods while some use this annotation for the service layer methods. Where is it more appropriate to put the #Transactional and why?
Similarly where to put #Repository annotation. On the DAO interface or on the DAO implementation?
I have always used #Service and #Repository annotations on their implementations, but they can be put in either one. Although, putting it on a interface would mean that you won't be able to have more than one implementation, because you would get a NoUniqueBeanDefinitionException error.
In the case of #Transactional, it depends, but normally it goes on the service. If you want to be able to add various DB calls on one transaction, then it should go in the service. If you want to make small transactions, then on the DAO would be best, but then, you wouldn't be able to modify several tables in one single transaction. Another con of having it on the DAO, is that you won't be able to rollback multiple modifications, only the ones that are bing executed by the DAO.
EDIT
After several projects using Spring, each one of different proportions, I end up changing my own practices. I would like to add that even though adding #Transactional to the service layer isn't exactly bad practice, it can be negatively affect the performance of the application. So in my own experience, it is better to add it to the DAO/Repository layers and only add at function level in the service layer, if a transaction must be atomic.
One more thing, if you are using Spring Data, the #Repository must be added on the interface. Only if you extend the JpaRepository will you need to add the #Repository annotation on the implementation. In this case, the interface of the JpaRepository and the custom implementation will both have #Repository.

Multiple datasources in Spring Boot Repository Annotated Interface

My application is based on Spring Boot, Hibernate, MySQL using Spring Data JPA to stitch them.
Use case is to use slave db node for doing heavy read operations so as to avoid all traffic being served from master mysql node. One way of achieving this is to have multiple Entity Managers pointing to separate data sources(one to master and other to slave node). This way has been explained quite well in below SO questions and blogs.
Spring Boot, Spring Data JPA with multiple DataSources
https://scattercode.co.uk/2016/01/05/multiple-databases-with-spring-boot-and-spring-data-jpa/
Where I am stuck is to understand if there is a way I can inject different entity managers for different use cases in my Repository Annotated Interface.
The only way I see it can be done is extending repository with a custom implementation which gives uses custom entity manager annotated with relevant persistenceContext like below.
public interface CustomerRepository extends JpaRepository<Customer, Integer>, MyCustomCustomerRepository{
}
public class MyCustomCustomerRepositoryImpl implements MyCustomCustomerRepository {
#PersistenceContext(unitName = "entityManagerFactoryTwo")
EntityManager entityManager;
}
I would like to avoid doing this custom implementation. Any help around solving this use case(which I feel should be very common) would be appreciated.
NOTE: Entities are same in both databases so giving separate packages for entity scanning and similar solutions might not work.
Here is a nice sample you can use:
dynamic-datasource-routing-with-spring.
Inside you can find an AbstractRoutingDatasource + an interceptor for a custom annotation that wires the service method to a required database.
However you can just use datasource switch explicitly.
Below is the pull request that shows the diff and how I made it work with most configurations annotation driven instead of xml. It is based on cra6's answer above. i.e. using spring's RoutingDataSource capability.
https://github.com/himanshuvirmani/rest-webservice-sample/pull/1/files

How to avoid lazy initialization of spring-data repositories?

I have a bean post processor (RepoRegistry) that picks up spring-data repositories and puts them i a map to make them available by type (repoRegistry.getRepositoryFor(MyEntity.class)). It seems as if the repo beans are created lazily. As a workaorud I now have to autowire all repositories manually somwhere so that they get created and processed by the post processor.
Is there another way to declare that some (or at least all) spring data repositories are declared non-lazy? I tried to add #Lazy to the repository interfaces without success.
You're probably seeing this on a Spring Data version that is older than the Codd release train (e.g. Spring Data JPA 1.4.x). The Codd release train (and thus Spring Data JPA 1.5) switched this model to eager init by default. Prior to that, repository beans were only create if there had been an injection target.
We generally recommend to use the Repositories type we already provide with Spring Data Commons to obtain all repositories contained in a BeanFactory:
Repositories repositories = new Repositories(applicationContext);
repositories.getRepositoryFor(Person.class);
Add this method to RepoRegistry:
#Autowired
public void setReps( List<Repository> repos ) {...}
Note: I haven't used Spring Data, yet. You need to use the common interface type of all repos as type argument of the List.
Spring will then collect all beans which implement Repository and pass them into the setter as a list.

Scenario when we may be needing #Configurable in spring?

I have question about the need of using #configurable. I have gone through the blog that explains how to use #configurable. But the question that comes to my mind is, what can be the scenario when we need to use #configurable. I can think of two scenarios where it can be useful
In a legacy project, when we are already making any bean with new operator and we want to make it spring managed.
In a new project, we want to enforce that even if developer makes the bean with new operator, still it is spring managed.
Otherwise for new beans we can always declare them in applicationContext.xml and I do not see any need to declare them #configurable.
Please let me know if above understanding is correct or if I am missing something.
UPDATE:- Basically as per my understanding configurable is generally used to inject dependency when creating the object with new operator. But why would i be creating the object with new operator when i am using spring
#Configurable annotation is meant for injecting dependencies in domain-driven applications. That means, in such applications, the domain objects interact with each other to perform a certain operation.
Take the following example:
In an invoicing application, the Invoice class provides a constructor to create it, then it has methods to validate, and finally persist it. Now, to persist the invoice, you need a DAO implementation available within the invoice. This is a dependency you would like to be injected or located. With Spring's #Configurable, whenever an invoice is created using the new operator, the appropriate DAO implementation will get injected and can be used for all persist operations.
I had a more realtime scenario where I used #Configurable annotation as described here.

Resources