Principes et utilisation de la programmation asynchrone
Dans le développement Java, l'exécution asynchrone est esentielle pour les opérations longues comme les notifications matérielles ou l'envoi de SMS. L'annotation @Async de Spring permet de déléguer ces tâches à des threads séparés, préservant ainsi le flux principal.
Mécanisme sous-jacent de @Async
L'implémentation repose sur AOP et la création dynamique de proxies. Les méthodes annotées sont interceptées et exécutées dans un thread distinct via le gestionnaire d'exécution asynchrone. Important : les appels internes au même objet ignorent le proxy.
Activation de l'asynchrone
<code>@Configuration
@EnableAsync
public class ConfigurationAsynchrone {
// Configuration supplémentaire
}</code>
Utilisation pratique
<code>@Component
public class TacheImportation {
@Async
public void importerDonnées(Long idPlateforme, String json) {
// Logique métier
}
}</code>
Configuration des pools de threads
Paramétrage par défaut
Spring utilise SimpleAsyncTaskExecutor avec des paramètres par défaut problématiques : taille de queue illimitée et création threads sans contrôle.
Personnalisation via application.yml
<code>spring:
task:
execution:
pool:
taille-max: 10
taille-core: 4
duree-conservation: 5s
capacite-file: 500
prefixe-nom: async-</code>
Configuration programmatique
<code>@Bean("GestionnairePersonnalise")
public Executor gestionnairePersonnalise() {
ThreadPoolTaskExecutor gestionnaire = new ThreadPoolTaskExecutor();
gestionnaire.setCorePoolSize(8);
gestionnaire.setMaxPoolSize(20);
gestionnaire.setQueueCapacity(1000);
gestionnaire.setKeepAliveSeconds(30);
gestionnaire.setThreadNamePrefix("perso-");
gestionnaire.initialize();
return gestionnaire;
}</code>
Implémentations alternatives
- ThreadPoolTaskExecutor : Solution optimale avec paramètres configurables
- ConcurrentTaskExecutor : Adatpateur pour Executor Java standard
- SyncTaskExecutor : Simulation synchrone pour les tests
Aspects transactionnels
@Async crée un contexte transactionnel indépendant. Pour conserver les transactions, encapsulez les opérations dans des méthodes distinctes annotées @Transactional.
Retour de résultats
<code>@Async("GestionnairePersonnalise")
public Future<Map<Long, List<String>>> traiter(Long id) {
Map<Long, List<String>> resultat = service.recupererResultat(id);
return new AsyncResult<>(resultat);
}</code>
Résolution des problèmes courants
Activation manquante
Assurez-vous d'avoir appliqué @EnableAsync dans la classe d'initialisation.
Problème de callback
Dans les projets Spring Boot, vérifiez le support async du dispatcher :
<code>@Bean
public ServletRegistrationBean enregistrementDispatcher() {
ServletRegistrationBean enregistrement = new ServletRegistrationBean(new DispatcherServlet(), "/");
enregistrement.setAsyncSupported(true);
return enregistrement;
}</code>
Cas d'échec critiques
- Appels internes : La méthode async doit être appelée via le proxy
- Visibilité non publique : Les méthodes doivent être publiques
- Modificateurs restrictifs : Évitez static et final
- Gestion des beans : La classe doit être annotée @Service/@Component
- Scan des packages : Vérifiez les chemins de scan dans @ComponentScan