I am working with Spring Boot 2 and I would like my requests to be handled asynchronously.
In Java EE, one can use Asynchronous Processing for Asynchronous Servlets as in this link. The following is a related example:
#WebServlet(urlPatterns={"/asyncservlet"}, asyncSupported=true)
public class AsyncServlet extends HttpServlet { ... }
and the above allows to use AsyncContext.
But in Spring Boot, I have the following #RequestMapping. How do I make it handle requests in Asynchronous mode and also supporting AsyncContext? How do I leverage the use of an Asynchronous Web Servlet?
#RestController
public class myRestController {
#RequestMapping("{resource}/**")
public void resourceRequest (#PathVariable("resource") String resource) {
// example:
// ... some long running calls such as database communication
// ... convert request through AsyncContext ctx = req.startAsync();
// etc
}
}
Note that returning void is intentional.
I found the following SO answer How to register a servlet with enabled "async-supported" in Spring-Boot? saying that "Spring Boot will automatically register any Servlet beans in your application context with the servlet container. By default async supported is set to true so there's nothing for you to do beyond creating a bean for your Servlet." but I am not using any #WebServlet annotations anywhere in my program, just the #RestController annotation. So how do I ensure that I am benefitting from asyncSupported option?
Related
Set Context path differently for both Webservice and Rest
I have an application which contains both implementation of Webservices and Rest services and I am looking for an solution to set context path for both Webservices and Rest services differently using yml/properties file
How to configure servlet dispatcher to work properly?
I would like to have:
localhost:8080/ws/* - webservice
localhost:8080/web/* - MVC components
servlet:
context-path: "/ws"
It sets globally for both webservices and rest services , How to make it independent to each other with out programming?
Using Spring Boot (with Spring Starter Web) you could achive what are you asking for with the annotation #RequestMapping.
You could put #RequestMapping(value="/ws") on the class declaration of every rest controller and #RequestMapping(value="/web") for web controllers.
For both rest and web controller than you could use other annotations to specify method path, i.e #GetMapping(value="/methodPath").
#Controller
#RequestMapping(value="/web")
public class WebController{
#GetMapping(value="/method")
public String method(){
...
}
}
#RestController
#RequestMapping(value="/ws")
public class RestController{
#GetMapping(value="method")
public String method(){
...
}
}
I have the following controller in spring MVC
#GetMapping("/id/kw")
public ModelAndView industryWater(HttpServletRequest request) {
return someMAV
}
I want to cut into the execution of the controller based on customized annotation
#GetMapping("/id/kw")
#WaterBefore
#WaterAfter
public ModelAndView industryWater(HttpServletRequest request) {
return someMAV
}
I can probably inject some thing using BEAN postProcessor, but I don't know how to hook my injected part with the controller execution. Also I need to access the context request mav when implementing my water aspect.
I researched a bit BeanPostProcessor, Interceptor, but didn't manage to connect all pieces.
I think you need to use AOP in Spring. that is very useful. it`s using transaction management and using logging etc.
Spring AOP (Aspect-oriented programming) framework is used to modularize cross-cutting concerns in aspects. If you want a more simple definition you can think of them as a Interceptor but with more options configurations possible. In Spring there are two different constructs that get called “interceptors”. First, there are Handler Interceptors, which are part of the Spring MVC framework and give you the ability to add interceptor logic to requests. But you also have Method Interceptors, which are part of the Spring AOP framework. These are much more general mechanism than Handler Interceptors, but also potentially more complex. In AOP terminology, such interceptors provide a means of coding the “aspects” you’re talking about.
Like this :
#Pointcut(" execution (* com.your.controller.industryWater(..))")
public void pointcutDemo() {}
#Before("pointcutDemo())")
public void logBefore(){ }
#After("pointcutDemo())")
public void logAfter(){ }
link : https://www.mkyong.com/spring3/spring-aop-aspectj-annotation-example/
https://www.journaldev.com/2583/spring-aop-example-tutorial-aspect-advice-pointcut-joinpoint-annotations
http://www.baeldung.com/spring-mvc-handlerinterceptor
In my previous experience:
When using pure servlet, we define servlets so that it will serve requests that match specific urls.
When using struts2, we define a filter so that it will serve requests that match specific urls.
When using springMVC in a traditional xml configuration style, we define a dispatcher servlet so that it will serve requests that match specific urls.
But with spring-boot:
Seems no servlet or filter is defined explicitly. But it still could serve specific urls.
The questions is:
Is it still using servlet? If yes, how it get to serve urls without defining servlet or filter explicitly?
Additional related questions (base on tips from comments):
It seems the implementation of SpringBootServletInitializer will be invoked on deploy, but who is going to invoke it?
As you can see here in details, on startup, while initializing an embedded server (Tomcat by default), Spring Boot creates and registers DispatcherServlet as a servlet.
Spring then, as usual, scans your own classes (including the one you invoke SpringApplication.run() from) and sets corresponding mapping for your controllers, if you have any. For example mapping for /hello here:
#RestController
#EnableAutoConfiguration
public class TestSpring {
#RequestMapping("/hello")
String hello() {
return "Hello World!";
}
public static void main(String[] args) throws Exception {
SpringApplication.run(TestSpring.class, args);
}
}
I'm writing a non-blocking Spring Rest controller. My client should send a request and doesn't care for the response and doesn't need to wait.
This is my server code:
#RestController
#EnableAsync
public class testController {
#RequestMapping(value = "test", method = RequestMethod.GET)
public ResponseEntity<String> test() throws InterruptedException {
timeConsumingMethod();
System.out.println("I'm should be first");
return new ResponseEntity<String>("the server is processing your request", HttpStatus.OK);
}
#Async
private void timeConsumingMethod() throws InterruptedException {
Thread.sleep(1000*5);
System.out.println("I'm should be second!");
}
However, When I call http://localhost:8181/test using(POSTMAN, Chrome, etc...)
I get the following on the server log:
I'm should be second!
I'm should be first
AND only after waiting 5 seconds my browser shows:
the server is processing your request
Is that the correct way for a "send and forget" Behavior?
According to the doc page the #EnableAsync should be added on configuration class.
Enables Spring's asynchronous method execution capability, similar to
functionality found in Spring's XML namespace.
To be used on #Configuration classes as follows, where MyAsyncBean is
a user-defined type with one or more methods annotated with either
Spring's #Async annotation, the EJB 3.1 #javax.ejb.Asynchronous
annotation, or any custom annotation specified via the annotation()
attribute.
why don't you use this:
https://www.baeldung.com/spring-webclient-resttemplate
Webflux client seems to do the same. I was searching for a similar solution where 1 microservice calls multiple microservices async and this fits the model
One of my projects uses Spring MVC to handle URL mappings and dispatch logic. I have now to use a third party library which uses its own HttpServlet as the main entry point for its functionalities, but as it's an optional drop-in replacement for another library I can't just put the <servlet> declaration in the web.xml: I'd rather use a Controller and Spring profiles to switch between such implementations without having to edit the web.xml.
Is there anything offered OOTB by Spring to handle such cases? I don't seem to find it right away.
Thanks in advance!
Since registering the third party servlet in your web.xml is a no-go, I think your best bet would be to create a singleton instance of the servlet in your ApplicationContext, and then create a custom view that delegates to said servlet's service method.
You can see an example of custom views in action in this tutorial.
Answering my own question here just in case my approach can be useful to others.
There are two key factors I needed to consider:
the proper initialization of the servlet
give the servlet full control over the HTTP layer (e.g. setting HTTP headers, etc)
In my specific case there's no need for properly handling the servlet destruction, as it's a no-op.
I ended up writing a dedicated Controller, to be instantiated only if a specific Spring profile is activated, which takes care of instantiating and initializing the Servlet. Then, all the requests will be directly handled in a void handler method, as follows:
public class ServletDelegatingController implements ServletConfig {
private final DelegateServlet delegate = new DelegateServlet();
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
delegate.service(request, response);
}
// properly initializes the servlet
public void setServletConfig(ServletConfig servletConfig) {
try {
delegate.init(servletConfig);
} catch (ServletException e) {
throw new IllegalStateException("Failure while initializing the servlet", e);
}
}
}
The delegating-servlet.xml for the DispatcherServlet looks like the following:
<beans profile="custom">
<bean id="cmisServiceFactory"
class="com.foo.ServletDelegatingController"/>
</beans>