Java CDI – Sử dụng @Alternative để chọn một thay thế, Annotation @Produces

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.

Java CDI - Sử dụng @Alternative để chọn một thay thế, Annotation @Produces

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:

https://docs.oracle.com/javaee/7/tutorial/cdi-basic.htm

stackjava.com