call another service after sending the success response in spring boot? - java

The first controller is sending the success response after that it will call another method after sending the response.
I need to call m1()method after return the response
#RequestMapping(value = {"/hello"}, method = POST, produces = { "application/json" })
public Response getAllData(#RequestBody String request){
return new ResponseEntity<>("Hello World");
}
public void m1(){
}

The simple trick is to use try...finally.
try{
return new Response();
} finally {
//do after actions
}
'finally' will always execute after the try block no matter there is a return statement in it.

Example for the Spring AspectJ using #AfterReturning advice
#Aspect
#Component
public class A {
/*
* AfterReturning advice
*/
#AfterReturning("execution(* com.package.ClassName.getAllData(..))")
public void m1(JoinPoint joinPoint) {
}
}

You need to add #EnableAsync in your configuration class or main class
then create another service class encapsulating an Async method m1
In your class add the statement below:
asyncServiceImpl.m1();
#Service
public class AsyncServiceImpl {
#Async
public CompletableFuture<String> m1() {
// Your logic here
return CompletableFuture.completedFuture(String.valueOf(Boolean.FALSE));
}
}

you can use eventListener for creating event.
And catch it in public method with EventListener annotation.
https://www.baeldung.com/spring-events

The most simple and reliable way - run a thread. Try-final isn't good at all.
But the best solution is - throw out that SB and use pure JEE servlets to invoke all that you need (JSON, JPA, BM transactions) in the client's request's thread, so you will never get stuck like that.

Related

Can I return an API response without waiting on other external API calls in Spring Boot?

Is this the correct way to use #Async in Spring Boot?
#Service
class someServiceImpl {
...
public someResponseDTO getUsers(int userId) {
// Do some logic
...
// Call external API with another service method from another service impl
anotherService.emailUserInTheBackground(userId);
return someResponseDTO;
}
...
}
#Service
public class AnotherService {
#Async
public void emailUserInTheBackground(int userId) {
// This might take a while...
...
}
}
Since emailUserInTheBackground() has #Async annotation and void return type, does it block the line return someResponseDTO at all?
All I wanted is to return the response to the caller without waiting because emailUserInTheBackground() takes too long to complete and isn't directly tied to the response object.
Yes that is the correct way to run a task in the background, you can mimick the thread blocking behavior by introducing a delay.
#SpringBootApplication
#EnableAsync
public class MyApplication {
public static void main(String[] arg) {
SpringApplication.run(MyApplication.class);
}
}
then you need to mark the emailUserInTheBackground method with #Async annotation.
#Service
class AnotherService {
#Async
public void emailUserInTheBackground(int userId) {
try {
TimeUnit.SECONDS.sleep(10);
System.out.println("Print from async: "+ Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Now add one more logger after a method call, you'll see getUsers(...) call completing first in a different thread even though the emailService thread is blocked for 10 seconds.
anotherService.emailUserInTheBackground(userId);
System.out.println("Print from service: "+ Thread.currentThread().getName());
you can also use CompletableFuture to run a task in the background.
public someResponseDTO getUsers(int userId) {
// some other task
...
// Call external API with another service method from another service impl
CompletableFuture.runAsync(() -> anotherService.emailUserInTheBackground(userId))
return someResponseDTO;
}
The relevant behavior of #Async is documented in the Spring documentation:
You can provide the #Async annotation on a method so that invocation of that method occurs asynchronously. In other words, the caller returns immediately upon invocation, while the actual execution of the method occurs in a task that has been submitted to a Spring TaskExecutor.
In the case you're describing, since the emailUserInTheBackground method is annotated with #Async and Spring's asynchronous method execution capability is enabled, the emailUserInTheBackground method will return immediately, and the call will be processed in a separate thread. The someResponseDTO value will be be returned from the getUsers method while the emailUserInTheBackground method continues to be processed in the background.

what is the proper design for calling controller methods?

I have a controller that calls several methods of an external SOAP api and returns some data, for example
public class ExternalApplicationController {
#Autowired
private ExternalApplicationSoapService soapService;
public FirstResponse getFirst() {
return soapService.getFirst()
}
public SecondResponse getSecond() {
return soapService.getSecond()
}
public ThirdResponse getThird() {
return soapService.getThird()
}
...
}
Everything was clear before the client asked to process exceptions on each method call. Now any method of my controller can get SOAPFaultException, so i need to modify each method with a try / catch block like this:
...
public FirstResponse getFirst() {
try {
return soapService.getFirst()
catch (SOAPFaultException ex){
// do something similar for all methods
}
}
....
I guess i should use a generified utility class that handles the common logic, but i suppose that design principles would be broken in that way... There shouldn't be anything between controller and service by MVC...
Also it's not very natural to make a service that should call soapService because all his methods would duplicate logic... And I don't want to write try / catch at each controller method, because it's a clear code duplicate..
Is there any suitable pattern for this?

What's the use of return a Callable result in a controller return?

Someone like to use Callable to build the return value of the controller due to Spring mvc
such as:
#RestController
public class TController{
#GetMappint("helloWorld")
public Callable<String> demo(){
return new Callable<String>() {
#Override
public String call() throws Exception {
//do sth.
return "hello world";
}
};
}
}
I think it is Useless and equivalent to this example:
#RestController
public class TController{
#GetMappint("helloWorld")
public String demo(){
//do sth.
return "hello world";
}
}
it is that sure?
No, basically you're wrong.
There is a use case for returning Callable<String>. Lets say the service that you'll call from the controller runs for a long time. During this time, in a traditional model of thread-per-request, the tomcat thread that is meant to server connections will be stuck.
So starting with servlet 3.0 there is a way to run things asynchronously, and this is the way to do it in spring MVC:
In fact, returning callable from controller method instructs Spring MVC to invoke the task defined in the Callable in a different thread.
You might find this article relevant to your quesion

Feign Call from asynchronous method

I have Spring event Publisher and listener where the requirement is as below:
Trigger the event from some method.
Listen the event from listener class
As soon as event is listened Call another micro-service
So currently i am using openfeign to call another micro-service.
This call works fine when the listener method runs Synchronously and it fails when listener method is marked as #Async.
Below is the sample code:
Fiegn Interface configuration:
#AuthorizedFeignClient(name = "another-microservice")
public interface CustomFeignInterface {
#PostMapping("api/call")
public ResponseEntity<String> callMethod(#RequestBody Foo foo);
}
Spring event Listener:
#Component
public class FooEventListener {
#Autowired
private CustomFeignInterface customFeignInt;
#Async
#EventListener
public void handleCustomEvent(Foo foo) {
try {
ResponseEntity<String> res = customFeignInt.callMethod(foo);
} catch (Exception e) {
e.printStackTrace();
}
}
}
As per above code Call to another micro-service works perfect when i remove #Async but fails when i add #Async to FooEventListener.handleCustomEvent(..) method.
Somewhere i found that Feign does not support Async calls:
https://github.com/OpenFeign/feign/issues/361
But still i need async behavior how can i achieve that?

How can I get annotations on rpc method being called in grpc-java

I need to validate request before different rpc methods being called with different validators.
So I implemented validators like
class BarRequestValidator {
public FooServiceError validate(BarRequest request) {
if (request.bar.length > 12) {
return FooServiceError.BAR_TOO_LONG;
} else {
return null;
}
}
}
and add a custom annotation before my rpc method
class FooService extends FooServiceGrpc.FooServiceImplBase {
#Validated(validator = BarRequestValidator.class)
public void bar(BarRequest request, StreamObserver<BarResponse> responseObserver) {
// Validator should be executed before this line, and returns error once validation fails.
assert(request.bar <= 12);
}
}
But I found that I can't find a way to get annotation information in gRPC ServerInterceptor. Is there any way to implement grpc request validation like this?
You can accomplish this without having the annotation at all, and just using a plain ServerInterceptor:
Server s = ServerBuilder.forPort(...)
.addService(ServerInterceptors.intercept(myService, myValidator))
...
private final class MyValidator implements ServerInterceptor {
ServerCall.Listener interceptCall(call, headers, next) {
ServerCall.Listener listener = next.startCall(call, headers);
if (call.getMethodDescriptor().getFullMethodName().equals("service/method")) {
listener = new SimpleForwardingServerCallListener(listener) {
#Override
void onMessage(request) {
validate(request);
}
}
}
return listener;
}
}
Note that I'm skipping most of the boilerplate here. When a request comes in, the interceptor gets it first and checks to see if its for the method it was expecting. If so, it does extra validation. In the generated code you can reference the existing MethodDescriptors rather than copying the name out like above.

Categories

Resources