Tutorials  /  JavaScript

Spring @Async Annotation für Asynchronous Processing

Ccentron Redaktion · Februar 2024 ·5 Min. Lesezeit ·JavaScript, Tutorial

Die Spring @Async Annotation ermöglicht es uns, asynchrone Methoden in Spring zu erstellen. Lassen Sie uns @Async in diesem Tutorial über das Spring Framework erkunden. Wir werden unseren eigenen Service definieren und in diesem Beispiel Spring Boot 2 verwenden. Lassen Sie uns beginnen!

Spring @Async Annotation Beispiel

Wir werden Maven verwenden, um ein Beispielprojekt für die Demonstration zu erstellen. Um das Projekt zu erstellen, führen Sie den folgenden Befehl in einem Verzeichnis aus, das Sie als Arbeitsbereich verwenden werden:

Code
mvn archetype:generate -DgroupId=com.journaldev.asynchmethods -DartifactId=JD-SpringBoot-AsyncMethods -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

Wenn Sie Maven zum ersten Mal ausführen, dauert es einige Sekunden, um den Generate-Befehl auszuführen, da Maven alle erforderlichen Plugins und Artefakte herunterladen muss, um die Generierungsaufgabe zu erledigen.

Erstellung eines Projekts mit Maven

Sobald Sie das Projekt erstellt haben, können Sie es in Ihrer bevorzugten IDE öffnen. Der nächste Schritt ist das Hinzufügen der passenden Maven-Abhängigkeiten zum Projekt. Hier ist die pom.xml-Datei mit den entsprechenden Abhängigkeiten:

Code
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<dependencies>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

Schließlich, um alle JARs zu verstehen, die dem Projekt hinzugefügt wurden, als wir diese Abhängigkeit hinzugefügt haben, können wir einen einfachen Maven-Befehl ausführen, der es uns ermöglicht, einen kompletten Abhängigkeitsbaum für ein Projekt zu sehen, wenn wir einige Abhängigkeiten hinzufügen. Hier ist ein Befehl, den wir verwenden können:

Code
mvn dependency:tree
VM

Passende Infrastruktur bei centron

Node-Anwendungen wollen deployt werden: ccloud³ VMs mit vollem Root-Zugriff ab 3,12 € im Monat – oder gleich als Managed Server, wenn der Betrieb nicht bei Ihnen liegen soll. Cloud Server mieten →

Aktivierung der Async-Unterstützung

Die Aktivierung der Async-Unterstützung ist ebenfalls nur eine Frage einer einzigen Annotation. Abgesehen von der Aktivierung der asynchronen Ausführung werden wir auch Executor verwenden, die es uns ermöglichen, Thread-Limits zu definieren. Mehr dazu, wenn wir den Code schreiben:

Go
package com.journaldev.asynchexample;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;

@SpringBootApplication
@EnableAsync
public class AsyncApp {
    ...
}

Hier haben wir die @EnableAsync Annotation verwendet, die es Spring ermöglicht, asynchrone Methoden in einem Hintergrund-Thread-Pool auszuführen. Als nächstes fügen wir auch den erwähnten Executor hinzu:

Code
@Bean
public Executor asyncExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(2);
    executor.setMaxPoolSize(2);
    executor.setQueueCapacity(500);
    executor.setThreadNamePrefix("JDAsync-");
    executor.initialize();
    return executor;
}

Hier haben wir festgelegt, dass maximal 2 Threads gleichzeitig ausgeführt werden sollen und die Warteschlangengröße auf 500 eingestellt ist. Hier ist der vollständige Code der Klasse mit Import-Anweisungen:

Go
package com.journaldev.asynchexample;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;

@SpringBootApplication
@EnableAsync
public class AsyncApp {

    public static void main(String[] args) {
        SpringApplication.run(AsyncApp.class, args).close();
    }

    @Bean
    public Executor asyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2);
        executor.setMaxPoolSize(2);
        executor.setQueueCapacity(500);
        executor.setThreadNamePrefix("JDAsync-");
        executor.initialize();
        return executor;
    }
}

Als nächstes werden wir einen Service erstellen, der tatsächlich Thread-Ausführungen nutzt.

Spring @Async Annotation - Erstellung eines Modells

Wir werden eine öffentliche Movie API verwenden, die nur die Daten eines Films zurückgibt. Wir werden unser Modell dafür definieren:

Go
package com.journaldev.asynchexample;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public class MovieModel {

    private String title;
    private String producer;

    // standard getters and setters

    @Override
    public String toString() {
        return String.format("MovieModel{title='%s', producer='%s'}", title, producer);
    }
}

Wir haben @JsonIgnoreProperties verwendet, damit, wenn es mehr Attribute in der Antwort gibt, diese sicher von Spring ignoriert werden können.

Erstellung des Services

Es ist an der Zeit, unseren Service zu definieren, der die erwähnte Movie API aufrufen wird. Wir werden ein einfaches RestTemplate verwenden, um eine GET API zu treffen und Ergebnisse asynchron zu erhalten. Lassen Sie uns den Beispielcode betrachten, den wir verwenden:

Go
package com.journaldev.asynchexample;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.concurrent.CompletableFuture;

@Service
public class MovieService {

    private static final Logger LOG = LoggerFactory.getLogger(MovieService.class);

    private final RestTemplate restTemplate;

    public MovieService(RestTemplateBuilder restTemplateBuilder) {
        this.restTemplate = restTemplateBuilder.build();
    }

    @Async
    public CompletableFuture lookForMovie(String movieId) throws InterruptedException {
        LOG.info("Looking up Movie ID: {}", movieId);
        String url = String.format("https://ghibliapi.herokuapp.com/films/%s", movieId);
        MovieModel results = restTemplate.getForObject(url, MovieModel.class);
        // Artificial delay of 1s for demonstration purposes
        Thread.sleep(1000L);
        return CompletableFuture.completedFuture(results);
    }
}

Diese Klasse ist ein @Service, was sie für den Spring-Komponenten-Scan qualifiziert. Der Rückgabetyp der Methode lookForMovie ist CompletableFuture, was eine Anforderung für jeden asynchronen Service ist. Da die Zeit für die API variieren kann, haben wir eine Verzögerung von 2 Sekunden zu Demonstrationszwecken hinzugefügt.

Spring @Async Annotation - Erstellung eines Command Line Runners

Wir werden unsere App mit einem CommandLineRunner ausführen, der der einfachste Weg ist, um unsere Anwendung zu testen. Ein CommandLineRunner wird unmittelbar nachdem alle Beans der Anwendung initialisiert wurden ausgeführt. Lassen Sie uns den Code für CommandLineRunner sehen:

Go
package com.journaldev.asynchexample;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.util.concurrent.CompletableFuture;

@Component
public class ApplicationRunner implements CommandLineRunner {

    private static final Logger LOG = LoggerFactory.getLogger(ApplicationRunner.class);

    private final MovieService movieService;

    public ApplicationRunner(MovieService movieService) {
        this.movieService = movieService;
    }

    @Override
    public void run(String... args) throws Exception {
        // Start the clock
        long start = System.currentTimeMillis();

        // Kick of multiple, asynchronous lookups
        CompletableFuture page1 = movieService.lookForMovie("58611129-2dbc-4a81-a72f-77ddfc1b1b49");
        CompletableFuture page2 = movieService.lookForMovie("2baf70d1-42bb-4437-b551-e5fed5a87abe");
        CompletableFuture page3 = movieService.lookForMovie("4e236f34-b981-41c3-8c65-f8c9000b94e7");

        // Join all threads so that we can wait until all are done
        CompletableFuture.allOf(page1, page2, page3).join();

        // Print results, including elapsed time        // Print results, including elapsed time
        LOG.info("Elapsed time: " + (System.currentTimeMillis() - start));
        LOG.info("--> " + page1.get());
        LOG.info("--> " + page2.get());
        LOG.info("--> " + page3.get());
    }
}

Wir haben gerade das RestTemplate verwendet, um die Beispiel-API, die wir verwendet haben, mit einigen zufällig ausgewählten Film-IDs zu treffen. Wir werden unsere Anwendung ausführen, um zu sehen, welche Ausgabe sie zeigt.

Spring @Async Annotation - Anwendung ausführen

Wenn wir die Anwendung ausführen, werden wir die folgende Ausgabe sehen:

Code
2018-04-13  INFO 17868 --- [JDAsync-1] c.j.a.MovieService  : Looking up Movie ID: 58611129-2dbc-4a81-a72f-77ddfc1b1b49
        2018-04-13 08:00:09.518  INFO 17868 --- [JDAsync-2] c.j.a.MovieService  : Looking up Movie ID: 2baf70d1-42bb-4437-b551-e5fed5a87abe
        2018-04-13 08:00:12.254  INFO 17868 --- [JDAsync-1] c.j.a.MovieService  : Looking up Movie ID: 4e236f34-b981-41c3-8c65-f8c9000b94e7
        2018-04-13 08:00:13.565  INFO 17868 --- [main] c.j.a.ApplicationRunner  : Elapsed time: 4056
        2018-04-13 08:00:13.565  INFO 17868 --- [main] c.j.a.ApplicationRunner  : --> MovieModel{title='My Neighbor Totoro', producer='Hayao Miyazaki'}
        2018-04-13 08:00:13.565  INFO 17868 --- [main] c.j.a.ApplicationRunner  : --> MovieModel{title='Castle in the Sky', producer='Isao Takahata'}
        2018-04-13 08:00:13.566  INFO 17868 --- [main] c.j.a.ApplicationRunner  : --> MovieModel{title='Only Yesterday', producer='Toshio Suzuki'}

Wenn Sie genau hinsehen, wurden nur zwei Threads zur Ausführung in der App gemacht, nämlich JDAsync-1 und JDAsync-2.

Fazit

In dieser Lektion haben wir untersucht, wie wir die asynchronen Fähigkeiten von Spring mit Spring Boot 2 Processing nutzen können - asynchrones Verarbeiten

Jetzt 200 € Guthaben sichern

Testen Sie Ihr Setup auf ccloud³

Registrieren Sie sich in der ccloud³ und erhalten Sie 200 € Startguthaben für Ihr Projekt – z. B. für eine PostgreSQL-VM mit automatischen Backups.

centron Redaktion Technische Redaktion

Das Redaktionsteam von centron schreibt Anleitungen aus dem Betriebsalltag: getestet auf unserer eigenen Plattform, betrieben im Rechenzentrum in Hallstadt bei Bamberg.

Kategorie JavaScript
Teilen
Noch offene Fragen?

Our team will help you with your specific setup - in German or English, by people who run the platform themselves.

War dieses Tutorial hilfreich?

Your answer is stored anonymously and helps us improve our tutorials.

Kommentare

No comments yet - be the first to ask a question about this tutorial.

Sign in to comment

Comments are open to centron customers. Sign in to your account to ask a question about this tutorial.

Weiterlesen

Das könnte Sie auch interessieren

Jetzt kostenlos anfangen

Melden Sie sich an und erhalten Sie in den ersten 60 Tagen ein Guthaben von 200 € bei centron.

Dieses Werbeangebot gilt nur für neue Konten. Angebot ausschließlich für Gewerbetreibende.

Jetzt loslegen Sales kontaktieren