Panduan Pasukan Lucee MY

WireBox: dependency injection dalam CFML

WireBox dalam Lucee: map, bind, singleton dan autowire dengan contoh yang benar-benar dijalankan dalam rig, serta bila ia berbaloi berbanding new biasa.

WireBox: dependency injection dalam CFML
0
Kandungan

WireBox: dependency injection dalam CFML

WireBox ialah bekas dependency injection (DI) yang dibundel bersama ColdBox, tetapi ia boleh digunakan berdiri sendiri dalam mana-mana aplikasi CFML pada Lucee. Tugasnya satu sahaja: membina objek dan menghantar kebergantungannya secara automatik, supaya anda tidak perlu menulis new di merata-rata tempat dan mengikat satu komponen kepada satu lagi dengan ketat. Artikel ini menunjukkan cara memetakan komponen dengan map, mengambil tika dengan getInstance, mengawal skop singleton dan transient, dan menyuntik kebergantungan melalui pembina serta sifat. Semua contoh dijalankan dalam rig Lucee sebenar dengan ColdBox 8.3, jadi setiap blok kod di sini terbukti berfungsi, bukan sekadar dibaca daripada dokumentasi.

Apa Itu Dependency Injection dan Kenapa Ia Penting

Dalam CFML biasa, apabila satu komponen memerlukan komponen lain, anda menulis new di dalam komponen itu. Masalahnya muncul apabila anda mahu menukar pelaksanaan, contohnya menukar kadar cukai daripada nilai tetap kepada panggilan pangkalan data, atau menggantikan komponen sebenar dengan komponen palsu semasa ujian. Setiap new yang bertaburan ialah satu titik yang perlu anda sentuh semula.

Dependency injection membalikkan tanggungjawab itu. Komponen tidak lagi membina kebergantungannya sendiri; ia hanya mengisytiharkan apa yang ia perlukan, dan bekas seperti WireBox yang membina serta menghantarnya. Hasilnya komponen menjadi longgar gandingannya, lebih mudah diuji, dan lebih mudah ditukar. Jika anda baru kepada konsep komponen CFC, baca dahulu panduan fungsi dan komponen CFC sebelum meneruskan.

Menyediakan WireBox Tanpa ColdBox Penuh

Anda tidak perlu menghidupkan keseluruhan rangka kerja ColdBox untuk menggunakan WireBox. Muat turun ColdBox dan letakkan folder coldbox di bawah akar aplikasi anda, kemudian cipta Injector terus daripada laluan itu:

wb = new coldbox.system.ioc.Injector();

Satu baris itu memberi anda bekas DI yang lengkap. Tidak ada konfigurasi XML, tiada fail tetapan yang perlu diisi. Dalam rig artikel ini, ColdBox dipasang pada pemetaan /coldbox, jadi coldbox.system.ioc.Injector merujuk terus kepada kelas itu. Perhatikan bahawa anda memanggil getBinder() dahulu sebelum memetakan, kerana fungsi map bukan milik tika Injector; ia milik objek binder yang diambil melalui getBinder().

Pemetaan Asas: map, to dan getInstance

Cara paling terus untuk menggunakan WireBox ialah memetakan satu alias kepada satu laluan komponen, kemudian meminta tika melalui alias itu. Mulakan dengan komponen model yang ringkas:

component {
    function tambah(required numeric a, required numeric b) {
        return arguments.a + arguments.b;
    }
}

Simpan fail di atas sebagai Kalkulator.cfc di dalam folder model anda. Kemudian petakannya dan ambil tikanya:

wb = new coldbox.system.ioc.Injector();
wb.getBinder().map("kalkulator").to("uji.model.Kalkulator");
k = wb.getInstance("kalkulator");
writeOutput(k.tambah(2, 3));

Blok ini memulangkan 5. Tiga langkah yang berlaku: map("kalkulator") mendaftarkan alias, .to("uji.model.Kalkulator") menunjuk alias itu kepada komponen sebenar, dan getInstance("kalkulator") membina serta memulangkan tika. Laluan uji.model.Kalkulator ialah laluan komponen relatif kepada akar aplikasi; dalam projek anda ia mungkin model.Kalkulator atau com.syarikat.aplikasi.Kalkulator, jadi gantikan dengan struktur folder anda sendiri.

Autowire: getInstance Mengikut Laluan Terus

WireBox tidak mewajibkan anda memetakan setiap komponen secara eksplisit. Jika anda memanggil getInstance dengan laluan penuh komponen, WireBox akan membinanya terus tanpa pemetaan dahulu:

wb = new coldbox.system.ioc.Injector();
k = wb.getInstance("uji.model.Kalkulator");
writeOutput(k.tambah(4, 5));

Ini dipanggil autowire, dan ia memulangkan 9. Autowire berguna semasa anda mula, kerana ia membolehkan anda mengambil sebarang komponen tanpa menulis pemetaan terlebih dahulu. Kelemahannya ialah anda kehilangan nama alias yang pendek dan titik pusat konfigurasi, jadi untuk aplikasi yang lebih besar pemetaan eksplisit lebih mudah diselenggara.

Singleton dan Transient: Mengawal Skop Tika

Secara lalai WireBox membina tika baharu setiap kali anda memanggil getInstance. Ini dipanggil transient. Jika anda mahu satu tika dikongsi untuk seluruh hayat bekas, jadikannya singleton dengan asSingleton(). Bezanya jelas apabila komponen menyimpan keadaan. Pertimbangkan komponen yang menjana pengecam rawak semasa dibina:

component {
    function init() {
        variables.id = createObject("java", "java.util.UUID").randomUUID().toString();
        return this;
    }
    function id() { return variables.id; }
}

Dengan singleton, dua panggilan getInstance memulangkan tika yang sama:

wb = new coldbox.system.ioc.Injector();
wb.getBinder().map("kaunter").to("uji.model.Kaunter").asSingleton();
a = wb.getInstance("kaunter");
b = wb.getInstance("kaunter");
writeOutput(a.id() == b.id());

Blok ini memulangkan true kerana a dan b ialah objek yang sama, jadi id mereka sama. Tanpa asSingleton(), setiap panggilan menjana UUID baharu dan perbandingan itu memulangkan false. Gunakan singleton untuk perkara seperti sambungan, tetapan dan perkhidmatan tanpa keadaan; kekalkan transient untuk objek yang membawa keadaan per permintaan, contohnya objek borang atau entiti. Untuk konsep skop dan hayat pemboleh ubah yang mendasari ini, lihat panduan memahami scope dalam CFML.

Suntikan Pembina dengan initArg

Kebergantungan boleh dihantar melalui pembina semasa WireBox membina tika. Komponen dengan pembina init yang menerima nilai:

component {
    function init(numeric kadar = 0) {
        variables.kadar = arguments.kadar;
        return this;
    }
    function cukai(required numeric jumlah) {
        return arguments.jumlah * variables.kadar;
    }
}

Untuk menghantar hujah kepada pembina itu, gunakan initArg pada pemetaan:

wb = new coldbox.system.ioc.Injector();
wb.getBinder().map("kira").to("uji.model.KiraKiraan").initArg(name="kadar", value=0.06);
kk = wb.getInstance("kira");
writeOutput(kk.cukai(100));

Blok ini memulangkan 6 kerana kadar 0.06 didarab dengan jumlah 100. initArg mengambil nama hujah pembina dan nilainya, jadi WireBox menghantar nilai itu semasa membina tika, menimpa nilai lalai 0 yang diisytiharkan dalam pembina. Ini cara yang jelas untuk menyuntik tetapan masa jalan seperti kadar cukai atau nama persekitaran.

Suntikan Sifat dan mapDirectory

Cara ketiga ialah suntikan sifat, iaitu komponen mengisytiharkan kebergantungannya sebagai property dengan atribut inject, dan WireBox mengisinya selepas membina tika. Pertama komponen yang menjadi kebergantungan:

component {
    function kadar() { return 0.08; }
}

Kemudian komponen yang bergantung kepadanya:

component {
    property name="kadarCukai" inject;

    function cukai(required numeric jumlah) {
        return arguments.jumlah * variables.kadarCukai.kadar();
    }
}

WireBox perlu tahu bagaimana memenuhi sifat kadarCukai. Satu cara ialah memetakan nama sifat itu secara eksplisit kepada komponen yang betul:

wb = new coldbox.system.ioc.Injector();
wb.getBinder().map("kadarCukai").to("uji.model.KadarCukai");
i = wb.getInstance("uji.model.KiraInvois");
writeOutput(i.cukai(100));

Blok ini memulangkan 8, iaitu 100 didarab kadar 0.08. Perhatikan bahawa KiraInvois tidak pernah menulis new KadarCukai(); ia hanya mengisytiharkan property name="kadarCukai" inject dan WireBox menghantar tika KadarCukai ke dalam variables.kadarCukai. Untuk aplikasi yang mempunyai banyak komponen, memetakan satu per satu menjadi leceh, jadi mapDirectory mengimbas keseluruhan pakej dan memetakan setiap komponen mengikut namanya:

wb = new coldbox.system.ioc.Injector();
wb.getBinder().mapDirectory(packagePath="uji.model");
i = wb.getInstance("uji.model.KiraInvois");
writeOutput(i.cukai(100));

Blok ini juga memulangkan 8. Selepas mapDirectory, nama komponen KadarCukai tersedia sebagai pemetaan kadarCukai, jadi suntikan sifat berfungsi tanpa baris map yang berasingan.

Ringkasan Kaedah WireBox

Jadual berikut meringkaskan kaedah pemetaan yang dibincangkan di atas, semuanya diuji dalam rig:

TujuanKaedahContoh
Pemetaan asasmap("alias").to("laluan")map("kalkulator").to("uji.model.Kalkulator")
AutowiregetInstance("laluan.penuh")getInstance("uji.model.Kalkulator")
Singleton.asSingleton()map("kaunter").to("...").asSingleton()
Suntikan pembina.initArg(name="...", value=...).initArg(name="kadar", value=0.06)
Suntikan sifatproperty name="..." inject;property name="kadarCukai" inject;
Imbas pakejmapDirectory(packagePath="...")mapDirectory(packagePath="uji.model")
Nilai literaltoValue(nilai)map("kadar").toValue(0.08)

Bila Berbaloi Menggunakan WireBox

WireBox bukan alat yang wajib untuk setiap projek. Untuk skrip kecil atau aplikasi dengan dua tiga komponen, new biasa lebih ringkas dan tidak ada salahnya. WireBox mula berbaloi apabila komponen anda bertingkat, apabila anda mahu menukar pelaksanaan tanpa menyunting setiap tapak panggilan, dan apabila anda mahu menulis ujian unit yang menggantikan kebergantungan sebenar dengan komponen palsu. Keupayaan ujian itu paling ketara: dengan DI anda boleh memetakan versi palsu dan menguji satu komponen secara terpencil, jadi baca panduan ujian unit dengan TestBox untuk melihat hujung yang satu lagi. Untuk lapisan data, ORM dan WireBox hidup bersama dengan baik kerana perkhidmatan yang dibina WireBox boleh menyuntik komponen yang menggunakan ORM, jadi lihat pengenalan ORM Hibernate apabila aplikasi anda mula menyentuh pangkalan data. Akhir sekali, singleton WireBox sering menggantikan caching manual untuk perkhidmatan tanpa keadaan, tetapi caching data sebenar masih perlu dikendalikan berasingan, jadi rujuk panduan caching dan prestasi untuk gambar penuh.

Soalan Lazim

Adakah WireBox memerlukan ColdBox penuh untuk berfungsi?

Tidak. WireBox ialah modul berasingan dalam ColdBox, dan anda boleh menggunakannya berdiri sendiri dengan hanya mencipta new coldbox.system.ioc.Injector() selepas meletakkan folder coldbox di laluan komponen anda. Anda tidak perlu menghidupkan rangka kerja, penghala atau acara ColdBox.

Apakah perbezaan antara map dan getInstance?

map mendaftarkan alias dan menunjuknya kepada laluan komponen melalui binder, manakala getInstance membina dan memulangkan tika. Anda memetakan sekali untuk mengisytiharkan kebergantungan, kemudian memanggil getInstance setiap kali anda memerlukan tika sebenar. getInstance juga boleh dipanggil dengan laluan penuh untuk autowire tanpa pemetaan.

Bila saya perlu guna singleton dan bila transient?

Guna singleton untuk komponen tanpa keadaan atau yang mahal dibina, seperti sambungan, tetapan dan perkhidmatan kongsi, kerana satu tika dikongsi sepanjang hayat bekas. Guna transient, iaitu lalai WireBox, untuk objek yang membawa keadaan per permintaan seperti entiti atau borang, supaya setiap panggilan mendapat tika bersih.

Kenapa suntikan sifat saya gagal dengan mesej instance not found?

Sifat inject memerlukan WireBox tahu komponen mana yang perlu diisi. Sama ada petakan nama sifat itu secara eksplisit dengan map("kadarCukai").to("..."), atau imbas pakej dengan mapDirectory supaya komponen dipetakan mengikut nama. Tanpa salah satu daripadanya, WireBox melaporkan ia tidak dapat mencari tika untuk nama sifat itu.

Adakah saya patut menggantikan semua new dengan WireBox?

Tidak. Untuk skrip kecil dan aplikasi ringkas, new biasa lebih jelas dan mencukupi. Gunakan WireBox apabila kebergantungan mula bertingkat, apabila anda mahu menukar pelaksanaan tanpa menyunting banyak fail, atau apabila ujian unit memerlukan komponen palsu. Ia alat untuk mengurus kerumitan, bukan keperluan mutlak setiap baris kod.

0 komen

0 komen

Log masuk untuk menjawab atau memberi komen.

Log masuk