Java CDI – Sử dụng @Alternative để chọn một thay thế, Annotation @Produces
1. Sử dụng @Alternative để chọn một thay thế
Như ở bài trước chúng ta đã tìm hiểu, khi thực hiện Inject, nếu không tìm thấy cài đặt (class thừa kế) nào của đối tượng được inject với annotation @Default thì nó sẽ inject cài đặt được đánh dấu @Alternative
Tuy nhiên nếu có nhiều hơn 1 cài đặt được đánh dấu @Alternative ta cần chỉ rõ cài đặt nào được chọn trong file beans.xml
Ví dụ: chương trình kết nối tới các loại database khác nhau để thực hiện query.
Thư viện sử dụng:
<dependency> <groupId>javax.enterprise</groupId> <artifactId>cdi-api</artifactId> <version>2.0-PFD2</version> </dependency> <dependency> <groupId>org.jboss.weld.se</groupId> <artifactId>weld-se</artifactId> <version>2.4.3.Final</version> </dependency>
Interface ConnectDatabase khai báo method connect tới database.
package stackjava.com.cdidemo.dao; public interface ConnectDatabase { public void connect(); }
Các class ConnectDB2, ConnectMySQL, ConnectPostgreSQL sẽ thừa kế interface ConnectDatabase và cài đặt lại method connect tới database tương ứng (DB2, MySQL, PostgreSQL)
package stackjava.com.cdidemo.dao; @Alternative public class ConnectDB2 implements ConnectDatabase { public void connect() { System.out.println("Connect DB2 database"); } }
package stackjava.com.cdidemo.dao; @Alternative public class ConnectMySQL implements ConnectDatabase { public void connect() { System.out.println("Connect MySQL database"); } }
package stackjava.com.cdidemo.dao; @Alternative public class ConnectPostgreSQL implements ConnectDatabase { public void connect() { System.out.println("Connect PostgreSQL database"); } }
Class DAOUtils.java sẽ thực hiện sử dụng 1 cài đặt của ConnectDatabase để kết nối tới database và thực hiện query
package stackjava.com.cdidemo.dao; import javax.inject.Inject; import javax.inject.Named; @Named("daoUtils") public class DAOUtils { @Inject private ConnectDatabase conn; public void query() { conn.connect(); System.out.println("query database..."); } }
File beans.xml
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"> <alternatives> <class>stackjava.com.cdidemo.dao.ConnectDB2</class> </alternatives> </beans>
- Ở đây mình chọn sẽ sử dụng inject ConnectDB2
Demo:
package stackjava.com.cdidemo.main; import javax.enterprise.context.spi.CreationalContext; import javax.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.BeanManager; import org.jboss.weld.environment.se.Weld; import org.jboss.weld.environment.se.WeldContainer; import stackjava.com.cdidemo.dao.DAOUtils; public class MainApp { public static void main(final String[] args) { Weld weld = new Weld(); WeldContainer container = weld.initialize(); BeanManager bm = container.getBeanManager(); Bean<DAOUtils> bean = (Bean<DAOUtils>) bm.getBeans("daoUtils").iterator().next(); CreationalContext<DAOUtils> ctx = bm.createCreationalContext(bean); DAOUtils jdbc = (DAOUtils) bm.getReference(bean, DAOUtils.class, ctx); jdbc.query(); } }
Kết quả:
Connect DB2 database query database...
*Lưu ý: Nếu bạn vừa sử dụng annotation @Default, vừa khai báo thẻ <alternatives> trong file beans.xml thì nó sẽ ưu tiên class được khai báo trong thẻ <alternatives>
Download code ví dụ này tại đây
2. Sử dụng annotation @Produces
Nhiều lúc việc tạo một đối tượng khá phức tạp, thay vì tạo nó qua một khởi tạo, bạn có thể sử dụng factory class để tạo một thể hiện.
Để làm điều này trong CDI, bạn có thể sử dụng annotation @Produces trong Factory Class như sau:
package stackjava.com.cdidemo.dao; import javax.enterprise.inject.Produces; public class CDIFactory { @Produces ConnectDatabase createConnect() { System.out.println("create object connect database with producer"); return new ConnectMySQL(); } }
Khi thực hiện inject ConnectDatabase vào DAOUtils nó sẽ tự động inject một thể hiện của ConnectMySQL
Kết quả:
create object connect database with producer Connect MySQL database query database...
Download code ví dụ này tại đây
*Lưu ý:
– Trường hợp dùng @Produces để generate bean thì các bean trong phạm vi generate không được có annotation @Default (Các cài đặt của ConnectDatabase không được phép sử dụng @Default)
– Nếu vừa dùng @Produces và config <alternative> trong beans.xml thì ưu tiên config trong beans.xml
Sử dụng @Alternative để chọn một thay thế, Annotation @Produces
References: