Run two methods in a spring boot controller at the same time - java

I am spring boot beginner and I have a spring boot project which contain a controller and this controller contains two methods as shown bellow:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class Controller {
#GetMapping("/preliminate")
public void OpentextWebService(){
try {
OTService.threadOne();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#GetMapping("/final")
public void OpentextWebService2(){
OTService.threadTwo();
}
}
the problem is that when I run : localhost:8080/preliminate and localhost:8080/final at the same time, only the first one will work. So is there is any way to run them at the same time?
I did some research and I found the #Async way but unfortunately I did not know how to impliment it in my code specially that I don't have a Service or Configuration Class.

The best way to implement this, is with #Async methods,
Create a Bean for you job Async.
#SpringBootApplication
#EnableAsync
public class ApplicationRun {
public static void main(String[] args) {
SpringApplication.run(ApplicationRun.class, args);
}
#Bean("threadPool")
public TaskExecutor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(20);
executor.setMaxPoolSize(1000);
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setThreadNamePrefix("Async-");
return executor;
}
}
And then, create a service bean with a method like

#Async("threadPool")
public void asyncTask1(){
OTService.threadOne();
}

#Async("threadPool")
public void asyncTask2(){
OTService.threadTwo();
}
And finally, call this service methods on your controller. Thats maybe works for you!

Related

Spring Cache not working as a compute property

I want to use a mechanism for create a one time compute function. I try to use Spring Caching. But it does not working. Please help me to solve this problem. My code like as below,
Gradle Dependency
compile 'org.springframework.boot:spring-boot-starter-cache'
Main Class of Spring Boot Application
#SpringBootApplication
#EnableCaching
public class Application {
public static ApplicationContext applicationContext;
public static void main(String[] args) {
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
// todo: Try to save response text and request body
applicationContext = SpringApplication.run(Application.class, args);
}
#Bean
WebMvcConfigurer webMvcConfigurer(){
return new WebMvcConfigurer() {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/**")
.addResourceLocations("classpath:/")
.setCacheControl(CacheControl.maxAge(3600, TimeUnit.SECONDS).noTransform().mustRevalidate());
}
};
}
}
My Coputational property and Test method
public String test(){
return hello();
}
#Cacheable("hello")
public String hello(){
System.out.println("hello");
return "Hello";
}
The #Cacheable annotation caches the values when it is called from outside your #Bean so calling it from another method inside your bean will not work.
try something like
#Bean
public class CachingBean {
#Cacheable("hello")
public String hello(){
System.out.println("hello");
return "Hello";
}
}
#Service
public class CallerService {
#Autowired
private CachingBean cachingBean;
// Setters, constructors...
public String test(){
return cachingBean.hello();
}
}
And then it should work.
That's because the #Cacheable annotation creates a proxy around the method call when it is injected as a Bean, so a direct call (to an instance created directly) or an internal call are not intercepted and the caching mechanism does not even see those calls.
I still sometimes forget about it and get biten by it at the beginning :).
Cheers!

Spring Boot application run method periodically

I am playing with a simple Spring Boot application and RabbitMQ.
However I cannot figure out how to run a method periodically.
Here is my Application class
#SpringBootApplication
public class SampleApp {
#Autowired
Sender sender;
public static void main(String[] args) {
SpringApplication.run(SampleApp.class, args);
}
#EventListener(ApplicationReadyEvent.class)
public void doSomethingAfterStartup() {
sender.sendMessage();
}
}
And the sendMessage method is defined as below
#Scheduled(fixedRate = 3000L)
public void sendMessage() {
log.info("Sending message...");
rabbitTemplate.convertAndSend("my-exchange", "my-routing-key", "TEST MESSAGE");
}
However this method is called only once, I can see only a single line in the console.
What I missed in my code?
Thanks.
Looks like you are missing #EnableScheduling:
#EnableScheduling
#SpringBootApplication
public class SampleApp {
...
}
Quoting the documentation:
Enables Spring's scheduled task execution capability, similar to functionality found in Spring's <task:*> XML namespace. To be used on #Configuration classes as follows:
#Configuration
#EnableScheduling
public class AppConfig {
// various #Bean definitions
}
This enables detection of #Scheduled annotations on any Spring-managed bean in the container.
I am usually using the Spring ThreadPoolTaskScheduler. You define it, as Bean for example then you wrap your method into a Runnable and you call it at intervals defined by a CronTrigger. The result can be retrieved using a ScheduledFuture
Check https://www.baeldung.com/spring-task-scheduler for a complete beginner tutorial.
Here's an alternative way if you don't want to rely on Spring's scheduler.
It's using rxjava2, here's an example:
#Component
public class MessagePublisher {
Sender sender;
Disposable d;
#Autowired
public Config(Sender sender) {
this.sender = sender;
this.d = doSomethingAfterStartup();
}
public Disposable doSomethingAfterStartup() {
return Observable.interval(3000, TimeUnit.MILLISECONDS).subscribe(tick -> {
sender.sendMessage();
});
}
}

Sharing an instance of a class across a spring boot application

I have a particular class used to interface with a service that requires initialization. In the application lifecycle, the only place this makes sense is in the start of the application because the rest of the spring application cannot run without it. I had the idea to do this:
#SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
try {
MyRequiredService mrs = new MyRequiredService();
mrs.connect(); // This will throw if it fails
run(MyApplication.class, args);
} catch(MyException e) {
System.out.println("Failed to connect to MyRequiredService!");
}
}
}
This will launch the service and attempt to connect but I have one big problem. How do I pass this class around the application? I need it's functions in the service endpoints I am writing.
I didn't see anything obvious and searching "passing class instance in spring boot application" turns up a bunch of unrelated topics.
Is there a smart, clean way to do this in spring boot? I apologize for a contrived example. The names of the service are unique enough I didn't want to violate any agreements.
You can make Spring do this for you. First, you need to annotate your class with #Service, so Spring will pick it up when scanning for classes.
Then, define an init() method and annotate it with #PostConstruct. Spring will instantiate your MyRequiredService class and call init()
#Service
public class MyRequiredService {
#PostConstruct
public void init() {
connect();
}
public void connect() {
// ...
}
}
You could call connect() from the constructor, but I don't like to define objects that may throw exceptions out of the constructor.
And then, you can use MyRequiredService in some other class by injecting it via the #Autowired annotation:
#Component
public class MyOtherClass {
private final MyRequiredService service;
public MyOtherClass(final MyRequiredService service) {
this.service = service;
}
// Other methods here.
}
This has the same overall effect as what you're trying to do above. If MyRequiredService fails, the application will not start up.
Make it a bean. Then it will be in the ApplicationContext which then you can pass to your desired other classes through the constructor
#Configuration
public class ApplicationConfiguration
{
#Bean
public MyRequiredService myRequiredService()
{
MyRequiredService mrs = new MyRequiredService();
try {
mrs.connect(); // This will throw if it fails
return mrs;
} catch(MyException e) {
log.error("Failed to connect to MyRequiredService!");
throw new IllegalStateException("MyRequiredService failed connection. Stopping startup");
}
}
#Bean
public SomeOtherService someOtherService(MyRequiredService mrs) {
return new SomeOtherService(mrs);
}
}
IMHO Instead of catching the error and logging it. I would throw it and stop the application from starting, but to keep with your example I added the throw IllegalStateException after the log.
Doing it this way Spring will create your MyRequiredService bean in the ApplicationContext then you can see I added as a parameter needed by the bean below that. Spring will grab that bean out of the ApplicationContext and supply it to the bean. If Spring doesn't find the bean in the ApplicationContext it will throw an error and stop the application from startup.
a class implements BeanFactoryPostProcessor which is init before normal bean
#Configuration
public class MyRequiredService implements BeanFactoryPostProcessor,
PriorityOrdered, InitializingBean {
#Override
public int getOrder() {
return Integer.MIN_VALUE;
}
public void connect() {
// ...
}
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
#Override
public void afterPropertiesSet() throws Exception {
connect();
}
}

Where should I put #EnableAsync annotation

I need to send a email in async way while saving the data into DB.
My approach was like this.
//I have tried with service layer annotating.But not worked.
#EnableAsync
class MyService{
public String saveMethod(List listOfData){
mail.sendEmailQuote(listOfData);
mail.sendEmailWorkflowTaskAssignment(listOfData);
myDao.saveData(listOfData);
}
}
I need to perform following methods in #Async way. Where should I put #EnableAsync annotation. This is not a Schedule related thing. This is happen when user click save button. Application is used flex spring blazeDS. There is no controller written by my self.
I have used #Async annotation in my code for following 2 methods. Those are in class call Mail.
#Async
sendEmailQuote(listOfData){}
#Async
sendEmailWorkflowTaskAssignment(listOfData){}
Could you help me to find where should I put #EnableAsync ?
I refer this sample
EnableAsync is used for configuration and enable Spring's asynchronous method execution capability, it should not be put on your Service or Component class, it should be put on your Configuration class like:
#Configuration
#EnableAsync
public class AppConfig {
}
Or with more configuration of your AsyncExecutor like:
#Configuration
#EnableAsync
public class AppConfig implements AsyncConfigurer {
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(7);
executor.setMaxPoolSize(42);
executor.setQueueCapacity(11);
executor.setThreadNamePrefix("MyExecutor-");
executor.initialize();
return executor;
}
}
Please refer to it's java doc for more details.
And for the tutorial you followed, EnableAsync is put above Application class, which extends AsyncConfigurerSupport with AsyncExecutor configuration:
#SpringBootApplication
#EnableAsync
public class Application extends AsyncConfigurerSupport {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("GithubLookup-");
executor.initialize();
return executor;
}
}
Just make sure that #Async methods aren't called by the same class. Self invocation for proxy won't work.

Spring Boot shutdown hook

How can I register/add a custom shutdown routine that shall fire when my Spring Boot application shuts down?
Scenario: I deploy my Spring Boot application to a Jetty servlet container (i.e., no embedded Jetty). My application uses Logback for logging, and I want to change logging levels during runtime using Logback's MBean JMX configurator. Its documentation states that to avoid memory leaks, on shutdown a specific LoggerContext shutdown method has to be called.
What are good ways to listen on Spring Boot shutdown events?
I have tried:
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext cac = SpringApplication.run(Example.class, args);
cac.addApplicationListener(new ApplicationListener<ContextClosedEvent>() {
#Override
public void onApplicationEvent(ContextClosedEvent event) {
logger.info("Do something");
}
});
}
but this registered listener does not get called when the application shuts down.
https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#features.spring-application.application-exit
Each SpringApplication will register a shutdown hook with the JVM to ensure that the ApplicationContext is closed gracefully on exit. All the standard Spring lifecycle callbacks (such as the DisposableBean interface, or the #PreDestroy annotation) can be used.
In addition, beans may implement the org.springframework.boot.ExitCodeGenerator interface if they wish to return a specific exit code when the application ends.
have you tried this as mentioned by #cfrick ?
#SpringBootApplication
#Slf4j
public class SpringBootShutdownHookApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootShutdownHookApplication.class, args);
}
#PreDestroy
public void onExit() {
log.info("###STOPing###");
try {
Thread.sleep(5 * 1000);
} catch (InterruptedException e) {
log.error("", e);;
}
log.info("###STOP FROM THE LIFECYCLE###");
}
}
Your listener is registered too late (that line will never be reached until the context has already closed). It should suffice to make it a #Bean.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
#SpringBootApplication
#EnableAutoConfiguration
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#NotNull
#Bean
ServletListenerRegistrationBean<ServletContextListener> myServletListener() {
ServletListenerRegistrationBean<ServletContextListener> srb =
new ServletListenerRegistrationBean<>();
srb.setListener(new ExampleServletContextListener());
return srb;
}
}
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class ExampleServletContextListener implements ServletContextListener {
#Override
public void contextInitialized(
ServletContextEvent sce) {
// Context Initialised
}
#Override
public void contextDestroyed(
ServletContextEvent sce) {
// Here - what you want to do that context shutdown
}
}
I have a similar use case, where I have to hold the server's shutdown process for some minutes, I have used the same approach mentioned in the question, the only change is instead of adding the listener after booting the service, I have added the listener (ContextClosedEvent) before running the application
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(Application.class);
application.addListeners((ApplicationListener<ContextClosedEvent>) event -> {
log.info("Shutdown process initiated...");
try {
Thread.sleep(TimeUnit.MINUTES.toMillis(5));
} catch (InterruptedException e) {
log.error("Exception is thrown during the ContextClosedEvent", e);
}
log.info("Graceful Shutdown is processed successfully");
});
application.run(args);
}
}

Categories