Bagaimana cara menyuntikkan komponen mirip layanan ke objek domain Grails?

Saya belum pernah menggunakan layanan Grails sebelumnya, tetapi menurut pencarian Web saya, layanan tersebut dapat disuntikkan ke objek domain. Jadi, jika saya memiliki kelas domain berikut (asumsikan BookService didefinisikan di suatu tempat),

class Book {

    BookService bookService

}

ketika saya membuat instance objek Book menggunakan, def book = new Book(), book.bookService harus disetel?

Jika demikian, bagaimana jika saya ingin memasukkan layanan eksternal (atau komponen mirip layanan)? Misalnya, jika ada klien API ISBN yang tersedia, dapatkah saya mengharapkan grail untuk menyuntikkannya dengan cara yang sama? Misalnya, kliennya adalah IsbnApi, bagaimana cara saya menyuntikkan secara otomatis seperti layanan lain? Apakah kode di bawah ini akan berfungsi?

class Book {

    @Transient
    @Autowire
    IsbnApi isbnApi

}

Berdasarkan tanggapan sebelumnya terhadap pertanyaan ini, saya telah mendefinisikan kelas domain dengan cara ini:

class Book {

    static transients = ['isbnApi']

    IsbnApi isbnApi

}

Sekarang, mungkin hanya ini yang saya perlukan, namun saya juga ingin menguji apakah injeksi otomatis akan berfungsi bahkan tanpa harus menjalankan aplikasi. Dalam pengujian unit saya, saya harus mengatur "layanan" tiruan secara manual.

IsbnApi isbnApi = Mock()
Book book = new Book()
book.isbnApi = mockIsbnApi

Saya mencoba memeriksa injeksi otomatis dengan memindahkan pengujian ke test/integration dan mengatur kacang menggunakan doWithSpring.

def doWithSpring() {
    isbnApi = (InstanceFactoryBean, mockIsbnApi, isbnApi)
}

void "test automatic injection"() {
    given:
    IsbnApi isbnApi = Mock()
    Book book = new Book()
    //removed: book.isbnApi = mockIsbnApi

    expect:
    book.isbnApi //this fails
}

Saya juga menemukan informasi tambahan dari jawaban untuk pertanyaan serupa. Secara khusus,

Perhatikan bahwa karena Anda menggunakan 'def' Anda tidak perlu menambahkannya ke daftar transien. Apakah Anda mencoba mengaksesnya dari metode statis? Ini adalah kolom instance, jadi Anda hanya dapat mengaksesnya dari instance.


person Psycho Punch    schedule 22.09.2014    source sumber
comment
Di mana IsbnApi Anda disimpan? asyik/src?   -  person Lalit Agarwal    schedule 22.09.2014
comment
Bisa dimana saja: src/groovy, atau dari toples lain, dll.   -  person Psycho Punch    schedule 22.09.2014


Jawaban (2)


Berdasarkan konvensi, layanan Grails secara otomatis menjadi kandidat untuk injeksi ketergantungan (= layanan tersebut dapat disuntikkan ke kelas lain). Jika Anda ingin kelas lain Anda harus menambahkannya ke conf/spring/resources.groovy.

E.g.:

import foo.bar.IsbnApi

beans = {
  isbnApi(IsbnApi)
}

Lihat bagian dokumentasi Bean Builder.

Untuk memastikan bahwa bidang Anda tidak diperlakukan sebagai properti persisten, Anda dapat menggunakan bidang transients statis.

Misalnya:

class User {
  def grailsApplication
  static transients = ['grailsApplication']
}

Lihat dokumentasi sementara

person micha    schedule 22.09.2014
comment
Apakah ini cukup agar Grails tidak salah mengira def isbnApi sebagai properti persisten? Jika Grails menemukannya di resources.groovy apakah secara otomatis memperlakukannya sebagai properti yang disuntikkan, bukan properti yang persisten? Bagaimana saya bisa memverifikasi ini melalui pengujian unit? - person Psycho Punch; 22.09.2014
comment
Anda dapat menggunakan bidang transients untuk ini (memperbarui jawabannya) - person micha; 22.09.2014
comment
Apakah ada cara untuk menguji ini? doWithSpring sepertinya tidak berfungsi saat saya menelepon, misalnya Book book = new Book(). - person Psycho Punch; 22.09.2014
comment
Bisakah Anda lebih spesifik? Apa yang ingin Anda uji? Saya tidak berpikir doWithSpring dipanggil dalam pengujian unit. Mungkin itu yang disebut dalam tes integrasi. Selama pengujian unit Anda tidak memiliki konteks aplikasi pegas, sehingga injeksi ketergantungan tidak berfungsi. Anda harus melihat dokumentasi pengujian: grails.org/doc/latest/guide/ pengujian.html - person micha; 22.09.2014
comment
Saya ingin menetapkan perilaku tiruan pada layanan untuk menguji kelas domain. Saya ingin dapat secara otomatis menyuntikkan layanan tiruan seperti pada aplikasi yang sebenarnya berjalan sehingga saya dapat memverifikasi semuanya berfungsi seperti yang diharapkan. - person Psycho Punch; 22.09.2014
comment
Seperti yang saya katakan injeksi ketergantungan tidak berfungsi di unit test. Jadi, Anda harus menggunakan book.yourService = mockService;. Atau gunakan tes integrasi. - person micha; 22.09.2014
comment
Ya, itulah yang saya lakukan. Namun, hanya untuk menguji, saya memindahkan tes ke test/integration, menghapus book.youService = mockService, mendeklarasikan kacang di doWithSpring(), tetapi saya masih mendapatkan NullPointerException. - person Psycho Punch; 22.09.2014
comment
Anda harus membuat pertanyaan baru untuk ini dan memposting kode Anda di sana. Saya rasa ini tidak ada hubungannya dengan pertanyaan awal yang Anda ajukan di sini. - person micha; 22.09.2014
comment
@PsychoPunch tambahkan apa pun yang Anda lakukan pada deskripsi pertanyaan Anda. Dan juga kode. - person Lalit Agarwal; 22.09.2014
comment
@micha, Lalit Agarwal: Saya telah memperbarui pertanyaan untuk menambahkan detail. Menurut saya pertanyaan lanjutannya berkaitan dengan pertanyaan awal, karena, pada prinsipnya, kita hanya bisa percaya bahwa sesuatu berhasil jika kita bisa mengujinya dengan cara tertentu. - person Psycho Punch; 22.09.2014

Selain jawaban yang sudah diterima, mulai dari grails 3.2.x Anda harus mengaktifkan pengkabelan otomatis pada lokasi domain di blok pemetaan atau secara global di konfigurasi aplikasi

class Book {

    static transients = ['isbnApi']

    IsbnApi isbnApi

    static mapping = {
        autowire true
    }
}

Ini dinonaktifkan secara default untuk meningkatkan kinerja membaca jadi mungkin yang terbaik adalah mencari pendekatan alternatif daripada mengaktifkannya.

http://grailsblog.objectcomputing.com/posts/2017/05/09/injecting-a-service-into-a-domain-class.html

person jkrshw    schedule 06.11.2018