Friday, February 26, 2010

Dependency Injection Framework Spring di Java

Di tulisan yang lalu saya menuliskan secara singkat overview dari Spring. Nah, di kesempatan kali ini saya mencoba untuk menuliskan tentang IoC. Saya dasarkan pilihan fokus ke IoC karena setiap saya membaca artikel dari internet ataupun buku-buku referensi selalu mengutamakan pemahaman IoC terlebih dahulu.

Banyak sebutan-sebutan dari IoC yang saya dapat. Mulai dari Injection of Control sampai Inversion of Control. Ada 3 tipe juga di dalam IoC ini, yaitu Constructor Injection, Setter Injection, dan Interface Injection. Saya tidak begitu hafal urutan tipe-tipenya. Dari yang saya dapat, Spring itu bisa di kategorikan sebagai tipe Setter Injection dan Constructor Injection. Tetapi Spring lebih fokus ke Setter Injection.

Banyak framework yang juga menggunakan metode IoC termasuk Spring sendiri. Ada statemen menarik yang saya kutip dari situs Martin Fowler.

When these containers talk about how they are so useful because they implement "Inversion of Control" I end up very puzzled. Inversion of control is a common characteristic of frameworks, so saying that these lightweight containers are special because they use inversion of control is like saying my car is special because it has wheels.



Menurut saya pernyataan diatas cukup memberi alasan mengapa Spring lebih tepat bersanding dengan kata Dependency Injection. Karena kemampuannya untuk meng-inject dependency dari suatu objek dari objek lain.

Karena saya belum benar-benar masuk ke Coding, jadi saya hanya bisa memberikan contoh dengan kode program yang saya dapat dari internet untuk sementara ini.

Misalkan kita punya class DataProcessor yang berguna untuk mengolah data yang disimpan dalam dile file1.data seperti di bawah ini :
class DataProcessor…

public Result processData() {
    FileDataReader dataReader = new FileDataReader("/data/file1.data");
    Data data = dataReader.readData();
    return data.calculateResult();
}
client code…
DataProcessor fileDataProcessor = new DataProcessor();
Result result = fileDataProcessor.processData();

Dari kode tersebut bisa kita lihat kalau class DataProcessor membutuhkan FileDataReader. Jika kita punya sumber data lain, atau katakan kita migrasi ke sistem penyimpanan data lain. Maka kita harus merefisi (refactor istilahnya) class DataProcessor dengan mengubah class FileDataReader menjadi class yang lebih umum (lebih generic) dan reusable.

Hasil refactor kita buat seperti dibawah ini :
class DataProcessor…

    private DataReader dataReader;
    public DataProcessor(DataReader reader) {
        this.dataReader = reader;
    }

    public Result processData() {
        Data data = dataReader.readData();
        return data.calculateResult();
    }  
interface DataReader…

    public Data readData();

client code…
FileDataReader dataReader = new FileDataReader("/data/file1.data");
DataProcessor fileDataProcessor = new DataProcessor(dataReader);
Result result = fileDataProcessor.processData();

Bisa kita lihat kalau DataReader sekarang lebih generic dan reusable berkat bentuk barunya sebagai interface. DataProcessor tidak lagi terikat dengan FileDataReader, tetapi lebih ke DataReader yang mengimplementasikan FileDataReader.

Tapi muncul satu masalah lagi. Setiap client ingin menggunakan DataProcessor, ia harus mencari lokasi dan menghubungkan FileDataReader seperti contoh diatas.

Dengan menggunakan Dependency Injection Spring, kita hanya perlu menuliskan kode berikut di client,

client code…
InputStream is = new FileInputStream("src/examples/spring/beans.xml");
BeanFactory factory = new XmlBeanFactory(is);
DataProcessor dataProcessor = (DataProcessor) factory.getBean("fileDataProcessor");
Result result = dataProcessor.processData();

Spring meng-handle pembuatan DataProcessor sesuai fungsinya juga sebagai Factory. Kita hanya perlu meminta Bean dari DataProcessor dari factory Spring. Namun sebelumnya kita diharuskan menuliskan dependency atau bean apa saja yang dibutuhkan di sebuah file XML eksternal untuk konfigurasinya. Contohnya seperti di bawah ini :





    
          class="examples.spring.DataProcessor"
          singleton="true">
                                                
          class="examples.spring.FileDataReader"
          singleton="true">
                         /data/file1.data            
    

Elemen-elemen di kutip dengan tag dan class-class dari  POJO (Plain Old Java Object) dari aplikasi kita tuliskan di antara tag .

Tag seperti contoh diatas artinya kita hanya membutuhkan satu instans objek dari class DataPrecessor yang di beri nama objek fileDataProcessor.
                                 
Kode diatas berarti di constructor DataProcessor, referensi argumen yang diberikan bernilai fileDataReader. Dengan kata lain, kita langsung merefensikan atau menghubungkan objek FileDataReader dengan DataProcessor. Secara tidak langsung kita  tak perlu lagi menggunakan keyword new untuk membuat objek FileDataReader, karena Spring akan secara otomatis membuatkannya saat dibutuhkan. Hebat !!

Dengan adanya file XML eksternal ini, kita dapat mendevelop berbagai aplikasi dengan mudah juga sangat membantu kita dalam testing aplikasi yang kita buat. Dan memodifikasi aplikasi dan dependency yang ada, karena objek-objek yang kita buat sudah loose coupling berkat Spring.


Sumber :      http://www.devx.com/Java/Article/21665/1954

No comments:

Post a Comment