Estoy usando Spring boot con @EnableScheduling y @EnableAsync .
Tengo un método que está anotado con @Scheduled . Tengo algunos métodos más, que están anotados con @Async .
Ahora llamo a estos métodos @Async en el método @Scheduled e imprimo el nombre del subproceso actual en los métodos asíncronos. Lo que veo es que todos tienen el mismo nombre de hilo, que de hecho es el hilo que ejecuta el método @Scheduled .
No veo la ejecución del método asíncrono. ¿Que esta mal aquí?
Aquí está mi clase de arranque de aplicación
@SpringBootApplication @EnableScheduling @EnableAsync public class ApplicationBoot { public static void main(String[] args) { SpringApplication.run(ApplicationBoot.class, args); } }Aquí está mi clase de programador
@Component public class TaskScheduler { private static final Logger logger = Logger.getLogger(TaskScheduler.class); @Scheduled(fixedDelay = 10000) public void ScheduledMethod() { methodOne(); methodTwo(); methodThree(); } @Async private void methodOne() { logger.info("Method one called by Thread : " + Thread.currentThread().getName() + " at " + new Date()); } @Async private void methodTwo() { logger.info("Method two called by Thread : " + Thread.currentThread().getName() + " at " + new Date()); } @Async private void methodThree() { logger.info("Method three called by Thread : " + Thread.currentThread().getName() + " at " + new Date()); } }Producción
Método uno llamado por Thread: pool-1-thread-1 el martes 04 de abril 16:32:27 IST 2017
Método dos llamado por Thread: pool-1-thread-1 el martes 04 de abril 16:32:27 IST 2017
Método tres llamado por Thread: pool-1-thread-1 el martes 04 de abril 16:32:27 IST 2017
Explicación
Spring crea un proxy alrededor de su instancia. ScheduledMethod llama internamente a 3 métodos, que no están proxificados y, por lo tanto, no son asíncronos.
Si invoca un método en una referencia de objeto, el método se invoca directamente en esa referencia de objeto, como se puede ver a continuación.
Vea esta pregunta Spring AOP no funciona, cuando el método se llama internamente dentro de un bean para una solución alternativa, pero el mejor es el propuesto en el documento The best approach (the term best is used loosely here) is to refactor your code such that the self-invocation does not happen...
Tenga en cuenta que el método privado tampoco es compatible :
Debido a la naturaleza basada en proxy del marco AOP de Spring, los métodos protegidos, por definición, no son interceptados, ni para los proxies JDK (donde esto no es aplicable) ni para los proxies CGLIB (donde esto es técnicamente posible pero no recomendable para fines AOP). Como consecuencia, cualquier punto de corte dado se comparará solo con métodos públicos.
Ejemplo de solución alternativa
@Component public class ServiceMethod { private static final Logger logger = Logger.getLogger(ServiceMethod .class); @Async public void methodOne() { logger.info("Method one called by Thread : " + Thread.currentThread().getName() + " at " + new Date()); } @Async public void methodTwo() { logger.info("Method two called by Thread : " + Thread.currentThread().getName() + " at " + new Date()); } @Async public void methodThree() { logger.info("Method three called by Thread : " + Thread.currentThread().getName() + " at " + new Date()); } } @Component public class TaskScheduler { private static final Logger logger = Logger.getLogger(TaskScheduler.class); @Autowired private ServiceMethod serviceMethod; @Scheduled(fixedDelay = 10000) public void ScheduledMethod() { serviceMethod.methodOne(); serviceMethod.methodTwo(); serviceMethod.methodThree(); } }Es posible que no haya configurado el Thread Pool con más Threads para su Scheduler .
de los documentos
Si no proporciona un atributo de tamaño de grupo, el grupo de subprocesos predeterminado solo tendrá un único subproceso.