L'exécution de tâches asynchrones est nouvelle pour moi au printemps. Pardonnez-moi donc si cela ressemble à une question idiote.
J'ai lu que l'annotation @Async est introduite à partir de Spring 3.x au niveau de la méthode. L'appel de cette méthode se produira de manière asynchrone . J'ai également lu que nous pouvons configurer ThreadPoolTaskExecutor dans le fichier de configuration Spring.
Ce que je ne comprends pas, c’est que la procédure d’appel d’une méthode annotée @Async à partir d’un exécuteur tak laisse supposer - AsyncTaskExecutor
Auparavant, nous faisions quelque chose comme dans un cours:
@Autowired protected AsyncTaskExecutor executor;
Et alors
executor.submit(<Some Runnable or Callable task>)
Je ne suis pas en mesure de comprendre la relation entre les méthodes annotées @Async et TaskExecutor.
J'ai essayé beaucoup de recherches sur Internet mais je ne pouvais rien obtenir à ce sujet.
Quelqu'un peut-il donner un exemple pour la même chose?.
Voici un exemple d'utilisation de @Async
:
@Async
void doSomething() {
// this will be executed asynchronously
}
Appelez maintenant cette méthode depuis une autre classe et elle s'exécutera de manière asynchrone. Si vous voulez une valeur de retour, utilisez Future
@Async
Future<String> returnSomething(int i) {
// this will be executed asynchronously
}
La relation entre @Async
et TaskExecutor
est que @Async
utilise une TaskExecutor
dans les coulisses. De la docs:
Par défaut, lorsque vous spécifiez @Async sur une méthode, l'exécuteur qui sera utilisé est celui fourni à l'élément 'piloté par les annotations', comme décrit ci-dessus. Toutefois, l'attribut value de l'annotation @Async peut être utilisé lorsqu'il est nécessaire d'indiquer qu'un exécuteur autre que celui par défaut doit être utilisé lors de l'exécution d'une méthode donnée.
Donc, pour configurer un exécuteur par défaut, ajoutez ceci à votre configuration printanière.
<task:annotation-driven executor="myExecutor" />
Ou d'utiliser un exécuteur particulier pour un usage unique, essayez
@Async("otherExecutor")
Exemple complet
Printemps config
@Configuration
@EnableAsync
@ComponentScan("com.async")
public class AppConfig {
@Bean
public AsyncManager asyncManger() {
return new AsyncManager();
}
@Bean
public AsyncExecutor asyncExecutor() {
return new AsyncExecutor();
}
}
Classe d'exécuteur créée, l'exécuteur que j'ai créé pour que spring prenne en charge la gestion des threads.
public class AsyncExecutor extends AsyncConfigurerSupport {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("Violation-");
executor.initialize();
return executor;
}
}
Créez un manager.
public class AsyncManager {
@Autowired
private AsyncService asyncService;
public void doAsyncTask(){
try {
Map<Long, ViolationDetails> violation = asyncService.getViolation();
if(!org.springframework.util.CollectionUtils.isEmpty(violation)){
violation.entrySet().forEach( violationEntry -> {System.out.println(violationEntry.getKey() +"" +violationEntry.getValue());});
}
System.out.println("do some async task");
} catch (Exception e) {
}
}
}
Configurez votre classe de service.
@Service
public class AsyncService {
@Autowired
private AsyncExecutor asyncExecutor;
@Async
public Map<Long,ViolationDetails> getViolation() {
// TODO Auto-generated method stub
List<Long> list = Arrays.asList(100l,200l,300l,400l,500l,600l,700l);
Executor executor = asyncExecutor.getAsyncExecutor();
Map<Long,ViolationDetails> returnMap = new HashMap<>();
for(Long estCode : list){
ViolationDetails violationDetails = new ViolationDetails(estCode);
returnMap.put(estCode, violationDetails);
executor.execute((Runnable)new ViolationWorker(violationDetails));
}
return returnMap;
}
}
class ViolationWorker implements Runnable{
private ViolationDetails violationDetails;
public ViolationWorker(ViolationDetails violationDetails){
this.violationDetails = violationDetails;
}
@Override
public void run() {
violationDetails.setViolation(System.currentTimeMillis());
System.out.println(violationDetails.getEstablishmentID() + " " + violationDetails.getViolation());
}
}
Modèle.
public class ViolationDetails {
private long establishmentID;
private long violation;
public ViolationDetails(long establishmentID){
this.establishmentID = establishmentID;
}
public long getEstablishmentID() {
return establishmentID;
}
public void setEstablishmentID(long establishmentID) {
this.establishmentID = establishmentID;
}
public long getViolation() {
return violation;
}
public void setViolation(long violation) {
this.violation = violation;
}
}
Tester pour courir
public class AppTest {
public static void main(String[] args) throws SQLException {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class);
ctx.refresh();
AsyncManager task= ctx.getBean(AsyncManager.class);
task.doAsyncTask();
}
}
Dans le fichier de configuration, il convient de mentionner une tâche avec annotation avec le nom du pool de threads et la méthode avec @Async (nom du pool) sera exécutée dans le cadre de ce pool. Cela crée une classe proxy pour celle qui possède l'annotation @Async et l'exécute pour chaque thread.
Vous pouvez ajouter @Async sur votre méthode et les éléments suivants dans votre contexte d'application.
<task:annotation-driven executor="asynExecutor"/>
<task:executor id="asynExecutor" pool-size="5" />