Small question on the #Timed annotation from Micrometer, and how to use it with a reactive #Repository from Spring please.
I have a #Repository interface which is very straightforward, not even custom queries.
#Repository
public interface MyRepository extends ReactiveCassandraRepository<MyPojo, String> {
Here the example is with reactive Cassandra, but any reactive repository will do.
I would like to time the execution of the default methods, the save, findById, findAll, basically, all the straightforward methods a #Repository offers.
By time, I mean the real time taken to insert the data or to retrieve the data.
(This is particularly useful to see the read and write performance over time, under high load, etc...)
Hence, I tried with great hope:
#Repository
#Timed("mysupertimer")
public interface MyRepository extends ReactiveCassandraRepository<MyPojo, String> {
But sadly, it is not working.
Just to avoid confusion, it is not working for the repository methods.
I have #Timed in my #Controller layer, and different places of #Service layer, I see all the other metrics fine.
Also, I am really hoping for an answer on annotating the #Repository please. I understand I can just #Timed "all the places in my project calling the repository", but I have 300 calls to repositories and will need to explain to any future contributor to also annotate his calls.
A solution directly on the #Repository layer would be amazing.
Many thanks!
It is now possible with the latest version of SpringBoot 2.5.0
https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.5-Release-Notes#timed-metrics-with-webflux
Related
I have a Spring boot application which has a UserRepository but I have not annotated that repository with #Repository but still my application works fine.
Why #Repository annotation is optional in Spring boot and what is the best practise that should we annotate it or not in repository classes.
It is working because spring will scan the class path and identify given class is repository (DAO) based on the imports, when use #Repositary spring context know how to handle expections like re-throw to pre defined methods ..etc, and also this annotation help readability of the code.
For #Repository annotation even if you haven't mentioned Spring recognizes the repositories by the fact that they are extending Repository interfaces like JPARepository or CrudRepository.
So, it's not mandatory to mention annotation, you can check in your code whether you have mentioned #EnableJpaRepositories("packages") above Main class or not. That might also be one of the reasons why it is working.
As per best practices for annotations, they have a purpose to fulfill, #Repository is important from a database connection perspective, where it has lots of proper exceptions throw, or pre-defined methods.
If you do not use the proper annotations, you may face commit exceptions overridden by rollback transactions. You will see exceptions during the stress load test that is related to roll-back JDBC transactions.
For more clarity have a look at this post
I assume you have somewhere implicitly or explicitly a EnableJpaRepositories annotation which scans all Spring repositories and your repositories are extending CrudRepository or other Spring Data base classes.
The annotation is only needed when defining you own repositories without using Spring Data mechanism. Note, that Repository is just a special Component, latter should also do it to have DI enabled, so this is more for better recognizing the purpose of the class.
#Repository is used to indicate interface that extends a jpa repository, for example. Notice in the example below, the interface extends the Beer class and the BeerQueries query interface.
package com.algaworks.brewer.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.algaworks.brewer.model.Beer;
import com.algaworks.brewer.repository.helper.beer.BeersQueries;
#Repository
public interface Beers extends JpaRepository<Beer, Long>, BeersQueries {
}
I'm working with PostgresSQL and I have the following interface:
#Repository
public interface ExampleRepository extends CrudRepository<ExampleEntity, Long> { }
Then I try to get the bean:
ExampleRepository repository = ctx.getBean(ExampleRepository.class);
Of course, I can't do that, because there's no implementation and eventually I get
NoSuchBeanDefinitionException: No qualifying bean of type 'ExampleRepository'
I know this is a wrong approach, but since I'm not enough experienced, I've got no idea how I can communicate with my database. Any example I searched only explained how to implement services & controllers in order to interact with db through Browser. But I want to do CRUD operation inside the java code.
Could anyone explain it to me? Any related sources would also be fine.
I am not sure how you are getting context (ctx) here.
But the common approach is #Repository is not needed instead, #EnableJPARepositories should be used in the #Configuration file. Then use #Autowired to inject the repository into your service class (where you want to execute operation from your repository bean)
You can refer below link for more details
https://mkyong.com/spring-boot/spring-boot-spring-data-jpa/
You don't need to create bean. It will created by the spring framework because you annotated your interface as #Repository .You need only #Autowired in your service class or where do you want to use this reference.
#Autowired
private ExampleRepository exampleRepository;
I migrated a Spring-Cloud-Function to use Functional Bean Registration.
I can register the Function that contains my application logic.
However my logic should be able to autowire a dynamodbRepository which I currently defined like this:
#EnableScan
public interface BookRepository extends CrudRepository<CodingTip, String> {
List<Book> findAllByAuthor(String author);
}
Since I am not scanning for beans anymore no bean is created of type BookRepository. This means that I have to register it myself. But I do not want to define the implementations of all the CRUD methods.
Currently I could write:
context.registerBean("repository", BookRepository.class, () -> new BookRepository(){ ... });
How would I register the BookRepository bean while still maintaining the advantages of all the CRUD methods being implemented for me?
Check out this incubator project called Spring Fu. Although it is written in Kotlin, it might help you find a way to do this.
Take a look here to see how Sébastien did it with a MongoDB database.
Creating a DynamoDB client and an implementation instead of using an annotated interface would be the way forward I guess.
Hope that helps! :)
I'm not sure if I understand it correctly so want to clarify.
If I want to create a repository for my entity eg.:
public interface BookRepository extends JpaRepository<Book, Id> {}
Should I annotate it with #Repository? According to this question #Repository annotation translates exceptions from SQL to persistence ones but doesn't JpaRepostiory already do that? What's the best practice - to annotate or not?
While using JpaRepository you don't need to annotate the interface with #Repository
It is just an interface and the concrete implementation is created dynamically as a proxy object by Spring and the JDBC Exceptions are handled there.
You need to use #Repository when you create a Custom DAO, so that spring creates a bean and handles the exception properly.
You need to annotate it with #Repository so spring knows it should instantiate that class as a bean. The #Component, #Service and #Repository annotations all serve the same purpose in that regard. #Repository narrows the scope to a service that specifically deals with obtaining and storing data.
I'm trying to implement transactions on a CrudRepository Interface. I'm a beginner with this and my current problem is that when receiving a lot of requests from different clients, I'm sometimes getting a duplicate.
To avoid that I wanted to use SQL Transactions and their implementation with Spring but I'm unable to get it working.
Here is how I've tried to do it :
#Repository
#EnableTransactionManagement
#Transactional
public interface ApplicationPackageDao extends CrudRepository<ApplicationPackage, Long> {
/**
* Find if a record exists for this package name ,
* #param packageName
* #return
*/
#Transactional
ApplicationPackage findByPackageName(String packageName);
}
However it doesn't seem to work.
I tried to add the #Transactionnal annotations earlier in the Java methods I'm calling but I can't get it working either.
How am I supposed to work with transactions on CrudRepository ?
Or am I using completely the wrong thing?
In addition to crm86's answer some more notes to the #Transactional annotation:
It seems to be best practice to annotate the entry points into your application (e.g. your web controller methods or the main method of a scheduled batch). By using the annotation attribute TxType you can ensure constraints/conditions in methods which are located deeper in your application (e.g. TxType.MANDATORY would throw if no trx-context is running, etc.).
The #Transactional annotation has only an effect if the class is loaded as spring bean (e.g. #Component annotation at class level).
Remember that only RuntimeException's lead to a rollback. If you want a checked Exception leading to a rollback you have to enumerate each such Exception by using the attribute rollbackOn.
The annotation at class level is valid for all public methods of this class. Method level annotations override those at the class level. The repeated annotation in your example above (first at class level, then at method level) has no effect.
What I suggest:
Check your context and configuration classes with #Configuration annotation. From the documentation:
The #EnableTransactionManagement annotation provides equivalent
support if you are using Java based configuration. Simply add the
annotation to a #Configuration class
#EnableTransactionManagement and only looks
for #Transactional on beans in the same application context they are
defined in
Then you could use #Transactional in your service even in a method
Hope it helps