Panduan untuk Perpustakaan Refleksi

1. Perkenalan

The Reflections perpustakaan bekerja sebagai scanner classpath. Ini mengindeks metadata yang dipindai dan memungkinkan kita untuk menanyakannya pada saat runtime. Itu juga dapat menyimpan informasi ini, sehingga kami dapat mengumpulkan dan menggunakannya kapan saja selama proyek kami, tanpa harus memindai ulang classpath lagi.

Dalam tutorial ini, kami akan menunjukkan cara mengkonfigurasi pustaka Refleksi dan menggunakannya dalam proyek Java kami.

2. Ketergantungan Maven

Untuk menggunakan Refleksi , kita perlu memasukkan ketergantungannya dalam proyek kita:

 org.reflections reflections 0.9.11 

Kami dapat menemukan versi terbaru perpustakaan ini di Maven Central.

3. Konfigurasi Refleksi

Selanjutnya, kita perlu mengkonfigurasi pustaka. Elemen utama dari konfigurasi ini adalah URL dan pemindai.

URL memberi tahu perpustakaan bagian mana dari jalur kelas yang akan dipindai, sedangkan pemindai adalah objek yang memindai URL yang diberikan.

Jika tidak ada pemindai yang dikonfigurasi, pustaka menggunakan TypeAnnotationsScanner dan SubTypesScanner sebagai default.

3.1. Menambahkan URL

Kita dapat mengkonfigurasi Refleksi baik dengan menyediakan elemen konfigurasi sebagai parameter konstruktor varargs, atau dengan menggunakan objek ConfigurationBuilder .

Misalnya, kita dapat menambahkan URL dengan membuat instance Refleksi menggunakan String yang mewakili nama paket, kelas, atau pemuat kelas:

Reflections reflections = new Reflections("com.baeldung.reflections"); Reflections reflections = new Reflections(MyClass.class); Reflections reflections = new Reflections(MyClass.class.getClassLoader());

Selain itu, karena Reflections memiliki konstruktor varargs, kita dapat menggabungkan semua jenis konfigurasi di atas untuk membuatnya:

Reflections reflections = new Reflections("com.baeldung.reflections", MyClass.class);

Di sini, kami menambahkan URL dengan menentukan paket dan kelas yang akan dipindai.

Kami dapat mencapai hasil yang sama dengan menggunakan ConfigurationBuilder :

Reflections reflections = new Reflections(new ConfigurationBuilder() .setUrls(ClasspathHelper.forPackage("com.baeldung.reflections"))));

Bersama dengan metode forPackage () , Classp ath Helpe r menyediakan metode lain, seperti forClass () dan forClassLoader () , untuk menambahkan URL ke konfigurasi.

3.2. Menambahkan Pemindai

Perpustakaan Refleksi dilengkapi dengan banyak pemindai bawaan:

  • FieldAnnotationsScanner - mencari anotasi bidang
  • MethodParameterScanner - memindai metode / konstruktor, lalu mengindeks parameter, dan mengembalikan jenis dan anotasi parameter
  • MethodParameterNamesScanner - memeriksa metode / konstruktor, lalu mengindeks nama parameter
  • TypeElementsScanner - memeriksa bidang dan metode, lalu menyimpan nama yang sepenuhnya memenuhi syarat sebagai kunci, dan elemen sebagai nilai
  • MemberUsageScanner - metode scan / konstruktor / penggunaan bidang
  • TypeAnnotationsScanner - mencari anotasi runtime kelas
  • SubTypesScanner - mencari kelas super dan antarmuka kelas, memungkinkan pencarian terbalik untuk subtipe
  • MethodAnnotationsScanner - memindai anotasi metode
  • ResourcesScanner - mengumpulkan semua sumber daya non-kelas dalam sebuah koleksi

Kita dapat menambahkan pemindai ke konfigurasi sebagai parameter konstruktor Refleksi .

Misalnya, mari tambahkan dua pemindai pertama dari daftar di atas:

Reflections reflections = new Reflections("com.baeldung.reflections"), new FieldAnnotationsScanner(), new MethodParameterScanner());

Sekali lagi, dua pemindai dapat dikonfigurasi dengan menggunakan kelas helper ConfigurationBuilder :

Reflections reflections = new Reflections(new ConfigurationBuilder() .setUrls(ClasspathHelper.forPackage("com.baeldung.reflections")) .setScanners(new FieldAnnotationsScanner(), new MethodParameterScanner()));

3.3. Menambahkan ExecutorService

Selain URL dan pemindai, Refleksi memberi kita kemungkinan untuk memindai jalur kelas secara asinkron dengan menggunakan ExecutorService .

Kita dapat menambahkannya sebagai parameter konstruktor Refleksi , atau melalui ConfigurationBuilder :

Reflections reflections = new Reflections(new ConfigurationBuilder() .setUrls(ClasspathHelper.forPackage("com.baeldung.reflections")) .setScanners(new SubTypesScanner(), new TypeAnnotationsScanner()) .setExecutorService(Executors.newFixedThreadPool(4)));

Pilihan lainnya adalah dengan memanggil metode useParallelExecutor () . Metode ini mengonfigurasi ExecutorService FixedThreadPool default dengan ukuran yang sama dengan jumlah prosesor inti yang tersedia.

3.4. Menambahkan Filter

Elemen konfigurasi penting lainnya adalah filter. Filter memberi tahu pemindai apa yang harus disertakan, dan apa yang harus dikecualikan, saat memindai classpath .

Sebagai gambaran, kita dapat mengkonfigurasi filter untuk mengecualikan pemindaian paket pengujian:

Reflections reflections = new Reflections(new ConfigurationBuilder() .setUrls(ClasspathHelper.forPackage("com.baeldung.reflections")) .setScanners(new SubTypesScanner(), new TypeAnnotationsScanner()) .filterInputsBy(new FilterBuilder().excludePackage("com.baeldung.reflections.test")));

Sekarang, hingga titik ini, kami telah membuat ikhtisar singkat tentang berbagai elemen konfigurasi Refleksi . Selanjutnya, kita akan melihat bagaimana menggunakan perpustakaan tersebut.

4. Querying Menggunakan Refleksi

Setelah memanggil salah satu konstruktor Refleksi , pemindai yang dikonfigurasi memindai semua URL yang disediakan. Kemudian, untuk setiap pemindai, pustaka meletakkan hasilnya di penyimpanan Multimap . Akibatnya, untuk menggunakan Refleksi , kita perlu meminta penyimpanan ini dengan memanggil metode kueri yang disediakan.

Mari kita lihat beberapa contoh metode kueri ini.

4.1. Subtipe

Mari kita mulai dengan mengambil semua pemindai yang disediakan oleh Refleksi :

public Set
    
      getReflectionsSubTypes() { Reflections reflections = new Reflections( "org.reflections", new SubTypesScanner()); return reflections.getSubTypesOf(Scanner.class); }
    

4.2. Jenis Beranotasi

Selanjutnya, kita bisa mendapatkan semua kelas dan antarmuka yang mengimplementasikan anotasi yang diberikan.

Jadi, mari kita ambil semua antarmuka fungsional dari paket java.util.function :

public Set
    
      getJDKFunctinalInterfaces() { Reflections reflections = new Reflections("java.util.function", new TypeAnnotationsScanner()); return reflections.getTypesAnnotatedWith(FunctionalInterface.class); }
    

4.3. Metode Beranotasi

Sekarang, mari gunakan MethodAnnotationsScanner untuk mendapatkan semua metode yang dianotasi dengan anotasi yang diberikan:

public Set getDateDeprecatedMethods() { Reflections reflections = new Reflections( "java.util.Date", new MethodAnnotationsScanner()); return reflections.getMethodsAnnotatedWith(Deprecated.class); }

4.4. Konstruktor Beranotasi

Selain itu, kita bisa mendapatkan semua konstruktor yang tidak digunakan lagi:

public Set getDateDeprecatedConstructors() { Reflections reflections = new Reflections( "java.util.Date", new MethodAnnotationsScanner()); return reflections.getConstructorsAnnotatedWith(Deprecated.class); }

4.5. Parameter Metode

Selain itu, kita dapat menggunakan MethodParameterScanner untuk menemukan semua metode dengan tipe parameter yang diberikan:

public Set getMethodsWithDateParam() { Reflections reflections = new Reflections( java.text.SimpleDateFormat.class, new MethodParameterScanner()); return reflections.getMethodsMatchParams(Date.class); }

4.6. Jenis Pengembalian Metode

Selanjutnya, kita juga dapat menggunakan pemindai yang sama untuk mendapatkan semua metode dengan tipe pengembalian yang diberikan.

Let's imagine that we want to find all the methods of the SimpleDateFormat that return void:

public Set getMethodsWithVoidReturn() { Reflections reflections = new Reflections( "java.text.SimpleDateFormat", new MethodParameterScanner()); return reflections.getMethodsReturn(void.class); }

4.7. Resources

Finally, let's use the ResourcesScanner to look for a given filename in our classpath:

public Set getPomXmlPaths() { Reflections reflections = new Reflections(new ResourcesScanner()); return reflections.getResources(Pattern.compile(".*pom\\.xml")); }

4.8. Additional Query Methods

The above were but a handful of examples showing how to use Reflections' query methods. Yet, there are other query methods that we haven't covered here:

  • getMethodsWithAnyParamAnnotated
  • getConstructorsMatchParams
  • getConstructorsWithAnyParamAnnotated
  • getFieldsAnnotatedWith
  • getMethodParamNames
  • getConstructorParamNames
  • getFieldUsage
  • getMethodUsage
  • getConstructorUsage

5. Integrating Reflections into a Build Lifecycle

Kami dapat dengan mudah mengintegrasikan Refleksi ke dalam build Maven kami menggunakan gmavenplus-plugin .

Mari kita konfigurasikan untuk menyimpan hasil pemindaian ke file:

 org.codehaus.gmavenplus gmavenplus-plugin 1.5   generate-resources  execute          

Nanti, dengan memanggil metode collect () , kita dapat mengambil hasil yang disimpan dan membuatnya tersedia untuk digunakan lebih lanjut, tanpa harus melakukan pemindaian baru:

Reflections reflections = isProduction() ? Reflections.collect() : new Reflections("com.baeldung.reflections");

6. Kesimpulan

Dalam artikel ini, kami menjelajahi perpustakaan Refleksi . Kami membahas berbagai elemen konfigurasi dan penggunaannya. Dan, akhirnya, kami melihat cara mengintegrasikan Refleksi ke dalam siklus proses build proyek Maven.

Seperti biasa, kode lengkap tersedia di GitHub.