Giriş
@Async metod void veya Future veya CompletableFuture dönmelidir. CompletableFuture dönen bir örnek burada. AsyncResult dönmeye gerek yokÖrnek - Polling
Bir örnek burada
AsyncConfigurer is an Interface provided by Spring, It provides two methods. One is if you want to override the TaskExecutor(Threadpool), another is an Exception handler where you can inject your exception handler so it can catch the uncaught exceptions.getAsyncExecutor metodu
@Configuration
@EnableAsync
public class ServiceExecutorConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(30);
taskExecutor.setMaxPoolSize(40);
taskExecutor.setQueueCapacity(10);
taskExecutor.initialize();
return taskExecutor;
}
}@Slf4j
@Configuration
public class BaseAsyncConfigurer implements AsyncConfigurer {
//replace default Async Executor with Customize One.
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(Runtime.getRuntime().availableProcessors());
executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors()*5);
executor.setQueueCapacity(Runtime.getRuntime().availableProcessors()*10);
executor.setThreadNamePrefix("replacedAsync-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
...
}@Slf4j @Configuration public class BaseAsyncConfigurer implements AsyncConfigurer { ... //override the getAsyncUncaughtExceptionHandler() method to return our // custom asynchronous exception handler: //!!! All the exception happened in @async will been handler here. @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return (Throwable ex, Method method, Object... params)-> { try { log.error("\n\n[Exception-Async-Handler] Class-Name: {}-{}\n Type: {}\nException: {}\n\n", method.getDeclaringClass().getName(),method.getName(), ex.getClass().getName(), ex.getMessage()); } catch (Throwable e) { log.error("catch Async Exception: {}", e); } }; } }
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;import java.lang.reflect.Method; public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler { @Override public void handleUncaughtException(Throwable throwable, Method method, Object... obj) { System.out.println("Message from exception - " + throwable.getMessage()); System.out.println("Method name " + method.getName()); } }
@Configuration public class AsyncConfig implements AsyncConfigurer { @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return new AsyncExceptionHandler(); } }
# Core number of threads. Default is 8
spring.task.execution.pool.core-size=10
# Maximum allowed number of threads. Default is 1
spring.task.scheduling.pool.size=5
spring.task.execution.pool.max-size=16spring.task.execution.pool.queue-capacity=100spring.task.execution.pool.keep-alive=10s
This changes the thread pool to use a bounded queue so that when the queue is full (100 tasks), the thread pool increases to maximum 16 threads. Shrinking of the pool is more aggressive as threads are reclaimed when they are idle for 10 seconds (rather than 60 seconds by default).
#Number of core threadsspring.task.execution.pool.core-size=10#Maximum number of threadsspring.task.execution.pool.max-size=20#Thread name prefixspring.task.execution.thread-name-prefix=test#There are other configurations that readers can configure themselves
All that @Async does is execute the methods of the object on another thread, where it gets the thread from a pool (which can be specified, so some operations can have a dedicated pool).Kısıtlar
Suppose you write a class and identify a method which will act as Async and put @Async on top of that method, now if you want to use that class from another class by creating local instance then it will not fire the async, It has to be picked up by Spring @ComponentScan annotation or created inside a class marked as @Configuration.2. Private metodlar @Async olamaz. Açıklaması şöyle.
Never use @Async on top of a private method as in runtime it will not able to create a proxy, so not working.Açıklaması şöyle.
3. @Async Anotasyonu - Sonuç Tipi yazısına taşıdımPlease note that proxy mode allows for the interception of calls through the proxy only; local calls within the same class cannot get intercepted that way.
@Slf4j
@Service
public class AsyncService {
@Autowired
public DataService dataService;
@Async
public void dbOperate(){
log.info("some logic here first");
dataService.allStep();
log.info("some logic later");
}
}
@Slf4j
@Service
public class DataService {
@Transactional
public void allStep(){
saveObj();
updateObj();
}
public void saveObj(){
log.info("Some data saved");
}
public void updateObj(){
log.info("Some another data updated");
}
}
TaskExecutor Arayüzü İle İlişkisiWhen you put an @Async annotation on a method, underlying it creates a proxy of that object where @Async is defined (JDK Proxy/CGlib) based on the proxyTargetClass property. Then Spring tries to find a thread pool associated with the context, to submit this method's logic as a separate path of execution to be exact it searches a unique TaskExecutor bean or a bean named as taskExecutor if not found then use default SimpleAsyncTaskExecutor.
When you annotate a method with @Async annotation, it creates a proxy for that object based on “proxyTargetClass” property.When spring executes this method, by default it will be searching for associated thread pool definition. Either a unique spring framework TaskExecutor bean in the context or Executor bean named “taskExecutor”. If neither of these two is resolvable, default it will use spring framework SimpleAsyncTaskExecutor to process async method execution.
<task:annotation-driven executor="myExecutor"
exception-handler="exceptionHandler"/>
<task:executor id="myExecutor" pool-size="7-42" queue-capacity="8"/>
Şöyle yaparız@Async("myExecutor")
public void asynchronousFunction() throws InterruptedException {
...
}
Another fact is that the class annotated with @EnableAsync must be a @Configuration as well.Örnek
@EnableAsync
@Configuration
public class AsyncConfiguration { }
mode Alanı@EnableAsync(mode = AdviceMode.ASPECTJ)
@EnableTransactionManagement(mode = AdviceMode.ASPECTJ)
this now becomes the default executor to run methods annotated with @AsyncAçıklaması şöyle. Yani bu sınıf yerine AsyncConfigurer arayüzünden de kalıtılabilir.
AsyncConfigurer is an Interface provided by Spring, It provides two methods One is if you want to override the TaskExecutor(Threadpool), another is an Exception handler where you can inject your exception handler so it can catch the uncaught exceptions. You can create your own class and implement that one directly. but I will not do that, as an alternative, I will use Spring AsyncConfigurerSupport class which is annotated by @Configuration and @EnableAsync, and provides a default implementation.getAsyncExecutor metodu
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;import org.springframework.context.annotation.Configuration;import org.springframework.scheduling.annotation.AsyncConfigurerSupport;import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;@Configurationpublic class AsynConfiguration extends AsyncConfigurerSupport {@Overridepublic Executor getAsyncExecutor() {ThreadPoolTaskExecutor executor = newThreadPoolTaskExecutor();executor.setCorePoolSize(3);executor.setMaxPoolSize(4);executor.setThreadNamePrefix("asyn-task-thread-");executor.setWaitForTasksToCompleteOnShutdown(true);executor.initialize();return executor;}@Overridepublic AsyncUncaughtExceptionHandlergetAsyncUncaughtExceptionHandler() {return new AsyncUncaughtExceptionHandler() {@Overridepublic void handleUncaughtException(Throwable ex,Method method, Object... params) {System.out.println("Exception: " + ex.getMessage());System.out.println("Method Name: " + method.getName());ex.printStackTrace();}};}}