Documentation says org.springframework.web.filter.OncePerRequestFilter "guarantees to be just executed once per request". Under what circumstances a Filter may possibly be executed more than once per request?
Under what circumstances a Filter may possibly be executed more than once per request?
You could have the filter on the filter chain more than once.
The request could be dispatched to a different (or the same) servlet using the request dispatcher.
A common use-case is in Spring Security, where authentication and access control functionality is typically implemented as filters that sit in front of the main application servlets. When a request is dispatched using a request dispatcher, it has to go through the filter chain again (or possibly a different one) before it gets to the servlet that is going to deal with it. The problem is that some of the security filter actions should only be performed once for a request. Hence the need for this filter.
To understand the role of OncePerRequestFilter, we need to first clearly understand how a normal filter behaves.
When you want some specific code to execute just before or after servlet execution, you create a filter which works as:
code1 ===> servlet execution (using chain.doFilter()) ===> code2
So code1 executes before servlet and code2 after servlet execution.
But here, while servlet execution, there can be some other request to a different servlet and that different servlet is also having this same filter. In this case, this filter will execute again.
OncePerRequestFilter prevents this behavior. For our one request, this filter will execute exactly one time (no more no less). This behavior is very useful while working with security authentication.
A special kind of GenericFilterBean was introduced to live in Servlet 3.0 environment. This version added a possibility to treat the requests in separate threads. To avoid multiple filters execution for this case, Spring Web project defines a special kind of filter, OncePerRequestFilter. It extends directly GenericFilterBean and, as this class, is located in org.springframework.web.filter package. OncePerRequestFilter defines doFilter method. Inside it checks if given filter was already applied by looking for "${className}.FILTER" attribute corresponding to true in request's parameters. In additionally, it defines an abstract doFilterInternal((HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) method. Its implementations will contain the code to execute by given filter if the filter hasn't been applied.
Under what circumstances a Filter may possibly be executed more than once per request?
A filter may be invoked as part of a REQUEST or ASYNC dispatches that occur in separate threads. We should use OncePerRequestFilter since we are doing a database call to retrieve the principal or the authenticated user, there is no point in doing this more than once. After that, we set the principal to the security context.
Authentication auth = jwtTokenProvider.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(auth);
where jwtTokenProvider is your service for getting authentication from the jwt token.
OncePerRequestFilter implements logic to make sure that the filter’s doFilter() method is executed only one time per request.
Related
Looking to make a service call based on a header value.
I can see two options:
1) Do it from the controller which is mainly used for a different service.
2) Add a filter which will do this by reading the request context.
Want to know what's the best way to handle this in a Spring application.
I guess it depends on your requirements.
Controller:
If you have to make service calls for preparing the response of a specific controller. For example, you have a controller say:
/employee
fand or preparing the response of this endpoint you need to call say staff service.
In this case, it's better to handle such calls in controllers.
Filter:
If you want to intercept each request and perform some operation on the request before sending it to the controller or before sending the response to the client.
A use case here can be checking the roles of the user by intercepting all requests.
As we know by using the filter, we can perform two operations at two instances −
Before sending the request to the controller
Before sending a response to the client.
In this case, OncePerRequestFilter is quite useful from the spring web module.
Quoting the documentation :
Filter base class that aims to guarantee a single execution per request dispatch, on any servlet container.
With springboot is there a way to make the default crud methods provided by the #RepositoryRestResource annotation asynchronous(with mongodb)? Meaning for example when i make 1000 save or find method(database) request, the thread doesnt wait for every single request to complete, it makes a new thread for each save() request, instead of executing each database request sequentially on one thread.
How can i call 3 different GET rest apis asynchronously in Spring Boot? Currently its taking alot of time to execute this apis sequentially. Let me know how to do this asynchronously?
You can use async-http-client as given in the following url : https://www.baeldung.com/async-http-client
2.You can use AsyncRestTemplate. In AsyncRestTemplate object you need to send the following three parameters.
* endpoint uri,
* request entity with headers,
*and response object.
Catch all those in to a ListenableFuture object where implement the override methods of callback in the case of failure and success.
For both of these approach, you have to create request objects and call the services. And the call backmethod will capture the result in the response objects. You can merge responses together and then do your business.
You can use #EnableAsync annotation at the configuration level to enable async processing and #Async at the method level which needs to be invoked asynchronously.
For further details please refer to the below link
https://www.baeldung.com/spring-async
I'm learning the source code of okhttp3, i have a little confuse that why okhttp create multiple chains (RealInterceptorChain) in each interceptor. Looks like only need one chain to manage the interceptor list.
Each chain instance behaves differently when proceed() is called. For example, the 3rd chain is the only one that calls the 4th chain.
I have a little bit trouble with Integration Test and the transactions.
I have a Rest Service System. Behind all I have a JPA-Repository, with a Postgres database. Now to test them I build JunitTest where I made the calls on the System. The test loads the web-context and an other xy-context where I have the configuration of security and database connections. On the test method I have the #Transactional annotation.
The test makes 2 requests (This is only one example I have more of similar scenarios on other Object):
insert a new user
on this user create a Group and after bind this to the user
The test makes the first call, and returns me a id where I use to perform the second call.
The second call take the id and make the post and there I have several problems.
Details of the second call:
Test make a post on a controller
Controller takes the request and forward it to the Service
Service method (with #Transactional) take the request and do:
a research to find the inserted user
insert a group object
update the user with the groupId (generated on point 2)
Now one of the problems I had, it was a AccessDeniedException on point 3.1, because I have also ACL, and I have to check if there are enough permissions.
One of the things that I tried to do is to set:
#Transactional(propagation=Propagation.REQUIRES_NEW)
on the Service Method.
What I get after is the result that the AccessDeniedException was disappeared but the research at 3.1 gives me empty result (the research is ok, because on other scenario I have correct results), but is strange because the first post was ok, and how I understand Spring handles the #Transactions and "commits" to database so that a commit is performed when a transaction is closed. This brings me to an other idea to try: remove the #Transaction annotation on the test, but when i made this, then the database has all the data of this scenario until the end of the tests session (If you have a lot of test this is not desirable), and this is not a very good thing.
Now I wrote a little bit where are my doubts, and problems without posting a lot of code and of privacy problems, but on request I can post little pieces of codes.
It's also probable that the approach is incorrect.
The questions are:
-how can I make this service work?
-It's the correct way to set (propagation=Propagation.REQUIRES_NEW)?
-It's the correct way to set #Transactional on the test? (eventually with a Rollback?)
Txs a lot.
To make test I use mockMvc to make the request and some annotation on the class:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(locations = { ..... })
#Transactional
public class tests {
#Test
public void aTest(){
mockMvc = MockMvcBuilders
.webAppContextSetup(webApplicationContext)
.addFilter(new DelegatingFilterProxy("springSecurityFilterChain", webApplicationContext), "/*")
.build();
mockMvc.perform(post(.....))
}
}
To answer your question:
It's the correct way to set #Transactional on the test? (eventually with a Rollback?)
No really, but you can. Because you are doing two requests, the second depends on the first, and http request will not remember your transaction, if you insist to do it, you need flush your session between requests.
It's the correct way to set (propagation=Propagation.REQUIRES_NEW)?
It depends. REQUIRES_NEW means it will start new transaction, the influence is that everything in the existing transaction will be invisible in the new transaction, because the old one is not commited yet! if this server is the entry point of the transaction, it makes no difference, but be aware of the visibility problem.
how can I make this service work?
OK, forget what my answers of the previous questions. If I have to write the test, I will do it this way:
The test is not transactional. If you are doing integration test, you don't need to rollback single tests. If you wanna rollback the commit, then you are having wrong task case, you should have two test cases insert user and update group.
3 parts of the test
Send request to insert user and get the ID (single transaction)
Send request to update group(another transaction)
Send request to fetch the user and do the checks.
Hope this can help you.