Burlando o @Async do Spring

RMAG news

É comum na construção de aplicações utilizando Spring, utilizarmos a anotação de @EnableAsync para habilitar execuções assíncronas e com o auxílio da @Async sobre os métodos facilmente torná-los assíncronos.

A @Async possui basicamente duas regras de utilização:

o método anotado deve ser público
o invocador do método não pode ser da mesma classe

No exemplo abaixo, não haverá problemas de compilação, porém o método (apesar de anotado com @Async) não terá a execução como o desejado.

@Slf4j
@Service
@RequiredArgsConstructor
public class HelloService {

public String get() {
log.info(“Chegou!”);
print();

return “Ola!”;
}

@Async
@SneakyThrows
public void print() {
Thread.sleep(Duration.ofSeconds(5));

log.info(“Burlado!”);
}
}

E é muito comum desejarmos que, por ser responsabilidade da classe, o bloco de código que deve ser executado assíncronamente se mantenha nela. Como resolver?

Simples!

Basta criarmos outra classe que auxilie, por exemplo:

@Service
public class AsyncService {

@Async
public void run(final Runnable runnable) {
runnable.run();
}

@Async
public <O> O run(final Supplier<O> supplier) {
return supplier.get();
}
}

Fazermos a injeção de dependência dessa bean onde é desejável a execução assíncrona e ainda por cima, poder tornar o método privado.

@Slf4j
@Service
@RequiredArgsConstructor
public class HelloService {

private final AsyncService asyncService;

public String get() {
log.info(“Chegou!”);

asyncService.run(this::print);

return “Ola!”;
}

@SneakyThrows
private void print() {
Thread.sleep(Duration.ofSeconds(5));

log.info(“Burlado!”);
}
}

Esse pequeno exemplo, demonstra a aplicação de vários conceitos e recursos: Inversão de Controle, Injeção de Dependência, SOLID, Design Pattern, Interfaces Funcionais.

Please follow and like us:
Pin Share