Cara Melakukan @Async pada Musim Bunga

1. Gambaran keseluruhan

Dalam artikel ini, kami akan meneroka sokongan pelaksanaan asinkron pada musim bunga - dan anotasi @Async .

Ringkasnya - penjelasan kaedah kacang dengan @Async akan menjadikannya dilaksanakan dalam utas yang berasingan iaitu pemanggil tidak akan menunggu penyelesaian kaedah yang disebut.

Salah satu aspek yang menarik pada musim bunga adalah bahawa sokongan acara dalam kerangka kerja juga mempunyai sokongan untuk pemprosesan async jika anda ingin melalui jalan tersebut.

2. Aktifkan Sokongan Async

Mari mulakan dengan mengaktifkan pemprosesan tak segerak dengan konfigurasi Java - dengan hanya menambahkan @EnableAsync ke kelas konfigurasi:

@Configuration @EnableAsync public class SpringAsyncConfig { ... }

Anotasi aktif cukup, tetapi seperti yang anda jangkakan, terdapat juga beberapa pilihan mudah untuk konfigurasi:

  • anotasi - secara lalai, @EnableAsync mengesananotasi @Async Springdan EJB 3.1 javax.ejb.Asynchronous ; pilihan ini boleh digunakan untuk mengesan jenis anotasi yang ditentukan pengguna lain juga
  • mod - menunjukkan jenis nasihat yang harus digunakan - JDK berasaskan proksi atau AspectJ tenunan
  • proxyTargetClass - menunjukkan jenis proksi yang harus digunakan - CGLIB atau JDK; atribut ini hanya berlaku sekiranya mod ditetapkan ke AdviceMode.PROXY
  • pesanan - menetapkan urutan di mana AsyncAnnotationBeanPostProcessor harus digunakan; secara lalai, ia berjalan terakhir, agar dapat mengambil kira semua proksi yang ada

Pemprosesan tak segerak juga dapat diaktifkan menggunakan konfigurasi XML - dengan menggunakan ruang nama tugas :

3. Anotasi @Async

Pertama - mari kita susun peraturan - @Async mempunyai dua batasan:

  • ia mesti digunakan untuk kaedah awam sahaja
  • permintaan diri - memanggil kaedah async dari dalam kelas yang sama - tidak akan berjaya

Sebabnya mudah - kaedahnya perlu diketahui umum agar dapat diproksi. Permintaan diri tidak berfungsi kerana memintas proksi dan memanggil kaedah yang mendasari secara langsung.

3.1. Kaedah Dengan Jenis Pengembalian Tidak Sah

Berikut adalah cara mudah untuk mengkonfigurasi kaedah dengan jenis pengembalian yang tidak sah untuk dijalankan secara tidak segerak:

@Async public void asyncMethodWithVoidReturnType() { System.out.println("Execute method asynchronously. " + Thread.currentThread().getName()); }

3.2. Kaedah Dengan Jenis Pulangan

@Async juga dapat diterapkan pada metode dengan jenis pengembalian - dengan membungkus pulangan sebenar di Masa Depan:

@Async public Future asyncMethodWithReturnType() { System.out.println("Execute method asynchronously - " + Thread.currentThread().getName()); try { Thread.sleep(5000); return new AsyncResult("hello world !!!!"); } catch (InterruptedException e) { // } return null; }

Spring juga menyediakan kelas AsyncResult yang menerapkan Masa Depan . Ini boleh digunakan untuk mengesan hasil pelaksanaan kaedah tak segerak.

Sekarang, mari kita gunakan kaedah di atas dan dapatkan hasil proses asinkron menggunakan objek Masa Depan .

public void testAsyncAnnotationForMethodsWithReturnType() throws InterruptedException, ExecutionException { System.out.println("Invoking an asynchronous method. " + Thread.currentThread().getName()); Future future = asyncAnnotationExample.asyncMethodWithReturnType(); while (true) { if (future.isDone()) { System.out.println("Result from asynchronous process - " + future.get()); break; } System.out.println("Continue doing something else. "); Thread.sleep(1000); } }

4. Pelaksana

Secara lalai, Spring menggunakan SimpleAsyncTaskExecutor untuk benar-benar menjalankan kaedah ini secara tidak segerak. Lalai boleh diganti pada dua peringkat - pada peringkat aplikasi atau pada tahap kaedah individu

4.1. Mengalahkan Pelaksana pada Tahap Kaedah

Pelaksana yang diperlukan perlu dinyatakan dalam kelas konfigurasi:

@Configuration @EnableAsync public class SpringAsyncConfig { @Bean(name = "threadPoolTaskExecutor") public Executor threadPoolTaskExecutor() { return new ThreadPoolTaskExecutor(); } }

Kemudian nama pelaksana harus diberikan sebagai atribut di @Async :

@Async("threadPoolTaskExecutor") public void asyncMethodWithConfiguredExecutor() { System.out.println("Execute method with configured executor - " + Thread.currentThread().getName()); }

4.2. Mengalahkan Pelaksana di Peringkat Permohonan

Kelas konfigurasi harus melaksanakan antara muka AsyncConfigurer - yang bermaksud bahawa ia mempunyai kaedah implementasi getAsyncExecutor () . Di sinilah kita akan mengembalikan pelaksana untuk keseluruhan aplikasi - ini sekarang menjadi pelaksana lalai untuk menjalankan kaedah yang dijelaskan dengan @Async :

@Configuration @EnableAsync public class SpringAsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { return new ThreadPoolTaskExecutor(); } }

5. Pengendalian Pengecualian

Apabila kaedah pengembalian kaedah adalah Masa Depan , pengendalian pengecualian mudah - Kaedah Future.get () akan membuang pengecualian.

Tetapi, jika jenis pengembalian tidak sah , pengecualian tidak akan disebarkan ke utas panggilan . Oleh itu kita perlu menambahkan konfigurasi tambahan untuk menangani pengecualian.

Kami akan membuat pengendali pengecualian async tersuai dengan melaksanakan antara muka AsyncUncaughtExceptionHandler . Kaedah handleUncaughtException () dipanggil apabila terdapat pengecualian asinkron yang tidak tertangkap:

public class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler { @Override public void handleUncaughtException( Throwable throwable, Method method, Object... obj) { System.out.println("Exception message - " + throwable.getMessage()); System.out.println("Method name - " + method.getName()); for (Object param : obj) { System.out.println("Parameter value - " + param); } } }

Pada bahagian sebelumnya, kami melihat antara muka AsyncConfigurer yang dilaksanakan oleh kelas konfigurasi. Sebagai sebahagian daripada itu, kita juga perlu mengganti kaedah getAsyncUncaughtExceptionHandler () untuk mengembalikan pengendali pengecualian asinkron tersuai kami:

@Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return new CustomAsyncExceptionHandler(); }

6. Kesimpulannya

Dalam tutorial ini, kami melihat menjalankan kod tak segerak dengan Spring . Kami bermula dengan konfigurasi dan anotasi yang sangat asas untuk membuatnya berfungsi tetapi juga melihat konfigurasi yang lebih maju seperti menyediakan pelaksana kami sendiri, atau strategi pengendalian pengecualian.

Dan, seperti biasa, kod penuh yang disajikan dalam artikel ini terdapat di Github.