Bagaimana cara menggunakan Spring FactoryBean?

1. Ikhtisar

Ada dua jenis kacang dalam wadah kacang musim semi: kacang biasa dan kacang pabrik. Musim semi menggunakan yang pertama secara langsung, sedangkan yang terakhir dapat menghasilkan objek sendiri, yang dikelola oleh kerangka kerja.

Dan, sederhananya, kita bisa membangun sebuah pabrik kacang dengan mengimplementasikan antarmuka org.springframework.beans.factory.FactoryBean .

2. Dasar-dasar Pabrik Kacang

2.1. Menerapkan FactoryBean

Mari kita lihat antarmuka FactoryBean terlebih dahulu:

public interface FactoryBean { T getObject() throws Exception; Class getObjectType(); boolean isSingleton(); }

Mari kita bahas tiga metode:

  • getObject () - mengembalikan objek yang diproduksi oleh pabrik, dan ini adalah objek yang akan digunakan oleh wadah Spring
  • getObjectType () - mengembalikan tipe objek yang diproduksi oleh FactoryBean ini
  • isSingleton () - menunjukkan jika objek yang diproduksi oleh FactoryBean ini adalah singleton

Sekarang, mari kita terapkan contoh FactoryBean . Kami akan menerapkan ToolFactory yang menghasilkan objek dengan tipe Tool :

public class Tool { private int id; // standard constructors, getters and setters }

The ToolFactory sendiri:

public class ToolFactory implements FactoryBean { private int factoryId; private int toolId; @Override public Tool getObject() throws Exception { return new Tool(toolId); } @Override public Class getObjectType() { return Tool.class; } @Override public boolean isSingleton() { return false; } // standard setters and getters }

Seperti yang bisa kita lihat, ToolFactory adalah FactoryBean , yang dapat menghasilkan objek Tool .

2.2. Gunakan FactoryBean Dengan Konfigurasi berbasis XML

Sekarang mari kita lihat cara menggunakan ToolFactory .

Kami akan mulai membuat alat dengan konfigurasi berbasis XML - factorybean-spring-ctx.xml :

Selanjutnya, kita dapat menguji apakah objek Tool diinjeksi dengan benar:

@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "classpath:factorybean-spring-ctx.xml" }) public class FactoryBeanXmlConfigTest { @Autowired private Tool tool; @Test public void testConstructWorkerByXml() { assertThat(tool.getId(), equalTo(1)); } }

Hasil pengujian menunjukkan bahwa kami berhasil memasukkan objek pahat yang dihasilkan oleh ToolFactory dengan properti yang kami konfigurasikan di factorybean-spring-ctx.xml .

Hasil pengujian juga menunjukkan bahwa container Spring menggunakan objek yang diproduksi oleh FactoryBean, bukan dirinya sendiri untuk injeksi dependensi.

Meskipun wadah Musim Semi menggunakan FactoryBean 's getObject () nilai kembali metode sebagai kacang, Anda juga dapat menggunakan FactoryBean itu sendiri.

Untuk mengakses FactoryBean , Anda hanya perlu menambahkan "&" sebelum nama kacang.

Mari kita coba mendapatkan pabrik kacang dan properti factoryId nya :

@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "classpath:factorybean-spring-ctx.xml" }) public class FactoryBeanXmlConfigTest { @Resource(name = "&tool") private ToolFactory toolFactory; @Test public void testConstructWorkerByXml() { assertThat(toolFactory.getFactoryId(), equalTo(9090)); } }

2.3. Gunakan FactoryBean Dengan Konfigurasi berbasis Java

Gunakan FactoryBean dengan konfigurasi berbasis Java adalah sedikit berbeda dengan konfigurasi berbasis XML, Anda harus memanggil FactoryBean 's getObject () metode eksplisit.

Mari kita ubah contoh di sub-bagian sebelumnya menjadi contoh konfigurasi berbasis Java:

@Configuration public class FactoryBeanAppConfig { @Bean(name = "tool") public ToolFactory toolFactory() { ToolFactory factory = new ToolFactory(); factory.setFactoryId(7070); factory.setToolId(2); return factory; } @Bean public Tool tool() throws Exception { return toolFactory().getObject(); } }

Kemudian, kami menguji apakah objek Alat disuntikkan dengan benar:

@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = FactoryBeanAppConfig.class) public class FactoryBeanJavaConfigTest { @Autowired private Tool tool; @Resource(name = "&tool") private ToolFactory toolFactory; @Test public void testConstructWorkerByJava() { assertThat(tool.getId(), equalTo(2)); assertThat(toolFactory.getFactoryId(), equalTo(7070)); } }

Hasil pengujian menunjukkan efek yang serupa dengan pengujian konfigurasi berbasis XML sebelumnya.

3. Cara Menginisialisasi

Sometimes you need to perform some operations after the FactoryBean has been set but before the getObject() method is called, like properties check.

You can achieve this by implementing the InitializingBean interface or using @PostConstruct annotation.

More details about using these two solutions have been introduced in another article: Guide To Running Logic on Startup in Spring .

4. AbstractFactoryBean

Spring provides the AbstractFactoryBean as a simple template superclass for FactoryBean implementations. With this base class, we can now more conveniently implement a factory bean which creates a singleton or a prototype object.

Let's implement a SingleToolFactory and a NonSingleToolFactory to show how to use AbstractFactoryBean for both singleton and prototype type:

public class SingleToolFactory extends AbstractFactoryBean { private int factoryId; private int toolId; @Override public Class getObjectType() { return Tool.class; } @Override protected Tool createInstance() throws Exception { return new Tool(toolId); } // standard setters and getters }

And now the nonsingleton implementation:

public class NonSingleToolFactory extends AbstractFactoryBean { private int factoryId; private int toolId; public NonSingleToolFactory() { setSingleton(false); } @Override public Class getObjectType() { return Tool.class; } @Override protected Tool createInstance() throws Exception { return new Tool(toolId); } // standard setters and getters }

Also, the XML config for these factory beans:

Now we can test if the Worker objects' properties are injected as we expect:

@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "classpath:factorybean-abstract-spring-ctx.xml" }) public class AbstractFactoryBeanTest { @Resource(name = "singleTool") private Tool tool1; @Resource(name = "singleTool") private Tool tool2; @Resource(name = "nonSingleTool") private Tool tool3; @Resource(name = "nonSingleTool") private Tool tool4; @Test public void testSingleToolFactory() { assertThat(tool1.getId(), equalTo(1)); assertTrue(tool1 == tool2); } @Test public void testNonSingleToolFactory() { assertThat(tool3.getId(), equalTo(2)); assertThat(tool4.getId(), equalTo(2)); assertTrue(tool3 != tool4); } }

As we can see from the tests, the SingleToolFactory produces singleton object, and the NonSingleToolFactory produces prototype object.

Note that there's no need to set singleton property in SingleToolFactory because, in AbstractFactory, singleton property's default value is true.

5. Conclusion

Menggunakan FactoryBean bisa menjadi praktik yang baik untuk merangkum logika konstruksi yang kompleks atau membuat konfigurasi objek yang sangat dapat dikonfigurasi lebih mudah di Spring.

Jadi dalam artikel ini, kami memperkenalkan dasar-dasar cara mengimplementasikan FactoryBean , cara menggunakannya dalam konfigurasi berbasis XML dan konfigurasi berbasis Java, dan beberapa aspek lain dari FactoryBean , seperti inisialisasi FactoryBean dan AbstractFactoryBean .

Seperti biasa, sumber lengkap di GitHub berakhir.