Beberapa seluk-beluk koleksi injeksi di Spring

Halo semuanya! Nama saya Vladislav Rodin. Saat ini saya mengajar kursus arsitektur perangkat lunak dan arsitektur perangkat lunak beban tinggi di portal OTUS. Sekarang di OTUS ada set terbuka untuk utas baru dari kursus Pengembang pada Kerangka Musim Semi . Untuk mengantisipasi dimulainya kursus, saya memutuskan untuk menulis sedikit materi hak cipta yang ingin saya bagikan kepada Anda.





Latar Belakang


Musim semi mengandung banyak "sihir" dalam dirinya sendiri, melakukan beberapa hal yang tidak terlihat dengan sendirinya. Ketidaktahuan atau kesalahpahaman tentang hal ini dapat menyebabkan efek samping yang mungkin Anda temui dalam proses penulisan aplikasi Anda menggunakan kerangka kerja ini.

Salah satu dari hal-hal yang tidak terlihat ini adalah injeksi antarmuka Java Collection Framework. Setelah secara mandiri menginjak menyapu yang terkait dengan topik ini, dan setelah mendengar pertanyaan-pertanyaan berikutnya dari rekan-rekan saya, saya memutuskan untuk mengatasinya dan mencatat hasil penelitian saya dalam bentuk artikel dengan harapan bahwa itu akan membantu seseorang yang sudah bekerja atau selama pengembangan awal Spring.

Skenario


Mari kita lihat layanan yang akan bekerja dengan para pahlawan film. Akan ada 3 dari mereka: Rambo, Terminator dan Gandalf. Masing-masing dari mereka akan mewakili kelas yang terpisah, dan orang tua mereka akan menjadi umum - Pahlawan.

public class Hero {
}

@Component
public class Rambo extends Hero {

    @Override
    public String toString() {
        return "Rambo";
    }
}

@Component
public class Terminator extends Hero {

    @Override
    public String toString() {
        return "Terminator";
    }
}


@Component
public class Gandalf extends Hero {
    @Override
    public String toString() {
        return "Gandalf";
    }
}

Daftar Injeksi


Mari kita asumsikan bahwa kita ingin menciptakan layanan yang akan bekerja dengan para pahlawan militan. Mungkin, Anda harus menyuntikkan daftar pahlawan seperti itu ke dalamnya.

Tidak masalah! Buat layanan dan konfigurasi:

@Service
@Getter
public class ActionHeroesService {
    @Autowired
    List<Hero> actionHeroes;
}

@Configuration
public class HeroesConfig {

    @Bean
    public List<Hero> action() {
        List<Hero> result = new ArrayList<>();
        result.add(new Terminator());
        result.add(new Rambo());
        return result;
    }
}

Semuanya baik-baik saja, tetapi ketika memeriksa dapat ditemukan bahwa Gandalf ada dalam daftar!

Spring, melihat bahwa perlu untuk menyuntikkan Daftar, berkeliling biji yang terletak dalam konteks, menemukan di antara mereka semua yang sesuai dengan jenis generik, mengumpulkan Daftar dari mereka dan menyuntikkannya, mengabaikan Daftar kami.

Bagaimana cara membuat Spring melakukan apa yang kita inginkan?

Opsi 1. Kruk


Karena masalahnya adalah tepatnya ketika mencoba menyuntikkan antarmuka Java Collection Framework, Anda cukup mengganti List dengan ArrayList di layanan dan, tentu saja, dalam konfigurasi sehingga Spring menemukan instance kelas yang kita butuhkan. Maka semuanya akan berjalan sesuai harapan

@Configuration
public class HeroesConfig {

    @Bean
    public ArrayList<Hero> action() {
        ArrayList<Hero> result = new ArrayList<>();
        result.add(new Terminator());
        result.add(new Rambo());
        return result;
    }
}

@Service
@Getter
public class ActionHeroesService {
    @Autowired
    ArrayList<Hero> actionHeroes;
}

Opsi 2. Lebih benar


Cara lain untuk mengikat tangan Spring adalah memintanya untuk menyuntikkan ke layanan tidak hanya Daftar apa pun, tetapi kacang dengan nama khusus, menambahkan Kualifikasi. Dengan demikian, kita akan dapat menyuntikkan kacang kita.

@Service
@Getter
public class ActionHeroesService {
    @Autowired
    @Qualifier("action")
    List<Hero> actionHeroes;
}

Peta Injeksi


Jika banyak orang tahu tentang nuansa suntikan Daftar, maka pada umumnya keadaan menjadi lebih buruk dengan Peta.
Mari kita menulis layanan yang akan bekerja dengan karakter utama film. Peta akan disuntikkan ke dalamnya, berisi nama-nama film dengan kunci, dan oleh nilai-nilai kacang karakter utama:

@Service
@Getter
public class MainCharactersService {
    @Autowired
    Map<String, Hero> mainCharactersByFilmName;
}

@Configuration
public class HeroesConfig {

    @Bean
    public Map<String, Hero> mainCharactersByFilmName() {
        Map<String, Hero> result = new HashMap<>();

        result.put("rambo", new Rambo());
        result.put("terminator", new Terminator());
        result.put("LOTR", new Gandalf());

        return result;
    }
}

Saat startup, Anda dapat melihat bahwa kunci Gandalf bukan LOTR, tetapi gandalf, dari mana kita dapat menyimpulkan bahwa itu bukan nama film yang ditulis, tetapi nama kacang, sedangkan dalam kasus Rimbaud dan terminator itu hanya beruntung: nama-nama karakter utama bertepatan dengan: judul film.

Bahkan, ketika diperlukan untuk menyuntikkan Peta, kuncinya adalah String, dan nilai kacang, Spring (seperti dalam kasus Daftar) hanya akan mengabaikan Peta yang kami usulkan, pergi melalui konteks dan kumpulkan semua kacang yang cocok s, dan akan membuat Peta dengan mereka sebagai nilai dan dengan nama mereka sebagai kunci.

Solusinya mirip dengan yang bekerja untuk Daftar:

Opsi 1. Kruk


Ganti Peta dengan HashMap:

@Service
@Getter
public class MainCharactersService {
    @Autowired
    HashMap<String, Hero> mainCharactersByFilmName;
}


@Configuration
public class HeroesConfig {

    @Bean
    public HashMap<String, Hero> mainCharactersByFilmName() {
        HashMap<String, Hero> result = new HashMap<>();

        result.put("rambo", new Rambo());
        result.put("terminator", new Terminator());
        result.put("LOTR", new Gandalf());

        return result;
    }
}

Opsi 2. Lebih benar


Tambahkan Kualifikasi:

@Service
@Getter
public class MainCharactersService {
    @Autowired
    @Qualifier("mainCharactersByFilmName")
    Map<String, Hero> mainCharactersByFilmName;
}

Source: https://habr.com/ru/post/undefined/


All Articles