Java CDI Inject nhiều kiểu vào cùng một bean, annotation @Qualifier

Java CDI Inject nhiều kiểu vào cùng một bean, annotation @Qualifier

Ở bài trước chúng ta đã tìm hiểu cách inject một cài đặt của một interface vào bean.  Vậy trường hợp muốn inject nhiều cài đặt khác nhau của một interface vào cùng một bean thì như thế nào?

Bài này mình sẽ hướng dẫn các cách inject nhiều kiểu vào cùng một bean, code ví dụ.

1. Inject nhiều kiểu vào cùng một bean sử dụng @Named

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, đồng bộ hóa dữ liệu giữa các loại database khác nhau.

Java CDI Inject nhiều kiểu vào cùng một bean, annotation @Qualifier

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;
@Named("connectDB2")
public class ConnectDB2 implements ConnectDatabase {

  public void connect() {
    System.out.println("Connect DB2 database");
  }

}
package stackjava.com.cdidemo.dao;
@Named("connectMySQL")
public class ConnectMySQL implements ConnectDatabase {

  public void connect() {
    System.out.println("Connect MySQL database");
  }

}
package stackjava.com.cdidemo.dao;

@Named("connectPostgreSQL")
public class ConnectPostgreSQL implements ConnectDatabase {

  public void connect() {
    System.out.println("Connect PostgreSQL database");
  }

}
  • Ở các class cài đặt của ConnectDatabase mình không sử dụng annotation @Default hay @Alternative mà mình sử dụng trực tiếp @Named và tên tương ứng cho từng cài đặt.

Class DAOUtils.java sẽ thực hiện sử dụng 2 cài đặt của ConnectDatabase để kết nối tới database và thực hiện đồng bộ hóa dữ liệu giữa hai database khác nhau

package stackjava.com.cdidemo.dao;

import javax.inject.Inject;
import javax.inject.Named;

@Named("daoUtils")
public class DAOUtils {

  @Inject
  @Named("connectMySQL")
  private ConnectDatabase conn1;

  @Inject
  @Named("connectDB2")
  private ConnectDatabase conn2;

 
  public void sync() {
    conn1.connect();
    conn2.connect();
    System.out.println("synchronize database...");
  }

}
  • Khi thực hiện inject, ta khai báo rõ bean nào sẽ được inject bằng cách sử dụng thêm annotation @Named và tên bean tương ứng

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 daoUtils = (DAOUtils) bm.getReference(bean, DAOUtils.class, ctx);
    daoUtils.sync();
  }
}

Kết quả:

Connect MySQL database
Connect DB2 database
synchronize database...

Download code ví dụ tại đây

2. Inject nhiều kiểu vào cùng một bean sử dụng @Qualifier

Mình tiếp tục sử dụng 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, đồng bộ hóa dữ liệu giữa các loại database khác nhau.

CDI Inject nhiều kiểu vào cùng một bean, annotation @Qualifier

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();
}

Định nghĩa các annotation mới với @Qualifier

package stackjava.com.cdidemo.qualifier;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.inject.Qualifier;

@Qualifier
@Retention(RUNTIME)
@Target({ TYPE, FIELD, METHOD, PARAMETER })
public @interface DB2 {

}
package stackjava.com.cdidemo.qualifier;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.inject.Qualifier;

@Qualifier
@Retention(RUNTIME)
@Target({ TYPE, FIELD, METHOD, PARAMETER })
public @interface MySQL {

}
package stackjava.com.cdidemo.qualifier;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.inject.Qualifier;

@Qualifier
@Retention(RUNTIME)
@Target({ TYPE, FIELD, METHOD, PARAMETER })
public @interface Postgre {

}

Khai báo các annotation tạo ở trên vào đầu các cài đặt của interface ConnectDatabase

package stackjava.com.cdidemo.dao;

import stackjava.com.cdidemo.qualifier.DB2;

@DB2
public class ConnectDB2 implements ConnectDatabase {

  public void connect() {
    System.out.println("Connect DB2 database");
  }

}
package stackjava.com.cdidemo.dao;

import stackjava.com.cdidemo.qualifier.MySQL;

@MySQL
public class ConnectMySQL implements ConnectDatabase {

  public void connect() {
    System.out.println("Connect MySQL database");
  }

}
package stackjava.com.cdidemo.dao;

import stackjava.com.cdidemo.qualifier.Postgre;

@Postgre
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 2 cài đặt của ConnectDatabase để kết nối tới database và thực hiện đồng bộ hóa dữ liệu giữa hai database khác nhau

package stackjava.com.cdidemo.dao;

import javax.inject.Inject;
import javax.inject.Named;

import stackjava.com.cdidemo.qualifier.DB2;
import stackjava.com.cdidemo.qualifier.MySQL;

@Named("daoUtils")
public class DAOUtils {

  @Inject
  @MySQL
  private ConnectDatabase conn1;

  @Inject
  @DB2
  private ConnectDatabase conn2;

  public void query() {
    conn1.connect();
    System.out.println("query database...");
  }

  public void sync() {
    conn1.connect();
    conn2.connect();
    System.out.println("synchronize database...");
  }

}
  • Khi thực hiện injection, thay vì sử dụng @Named ta sử dụng các annotation được định nghĩa riêng cho từng bean.

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 daoUtils = (DAOUtils) bm.getReference(bean, DAOUtils.class, ctx);
    daoUtils.sync();
  }
}

Kết quả:

Connect MySQL database
Connect DB2 database
synchronize database...

Download code ví dụ tại đây

Java CDI Inject nhiều kiểu vào cùng một bean, annotation @Qualifier

3. Sử dụng annotation @Qualifier với Enum

Ở ví dụ trên ta thấy với mỗi cài đặt lại phải tạo một annotation riêng cho nó như thế sẽ phải code khá nhiều.

Thay vì đó ta chỉ cần tạo một annotation kết hợp với Enum.

CDI Inject nhiều kiểu vào cùng một bean, annotation @Qualifier

package stackjava.com.cdidemo.qualifier;

public enum DatabaseType {
  MY_SQL, POSTGRE_SQL, DB2;
}
package stackjava.com.cdidemo.qualifier;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.inject.Qualifier;

@Qualifier
@Retention(RUNTIME)
@Target({ TYPE, FIELD, METHOD, PARAMETER })
public @interface TypeConnect {
  DatabaseType type() default DatabaseType.MY_SQL;
}

Các cài đặt của interface ConnectDatabase sẽ được đánh dấu với annotation TypeConnect với type tương ứng

package stackjava.com.cdidemo.dao;

import stackjava.com.cdidemo.qualifier.DatabaseType;
import stackjava.com.cdidemo.qualifier.TypeConnect;

@TypeConnect(type = DatabaseType.DB2)
public class ConnectDB2 implements ConnectDatabase {

  public void connect() {
    System.out.println("Connect DB2 database");
  }

}
package stackjava.com.cdidemo.dao;

import stackjava.com.cdidemo.qualifier.DatabaseType;
import stackjava.com.cdidemo.qualifier.TypeConnect;

@TypeConnect(type = DatabaseType.MY_SQL)
public class ConnectMySQL implements ConnectDatabase {

  public void connect() {
    System.out.println("Connect MySQL database");
  }

}
package stackjava.com.cdidemo.dao;

import stackjava.com.cdidemo.qualifier.DatabaseType;
import stackjava.com.cdidemo.qualifier.TypeConnect;

@TypeConnect(type = DatabaseType.POSTGRE_SQL)
public class ConnectPostgreSQL implements ConnectDatabase {

  public void connect() {
    System.out.println("Connect PostgreSQL database");
  }

}
  • Khi thực hiện inject, ta chỉ rõ annotation với type tương ứng
package stackjava.com.cdidemo.dao;

import javax.inject.Inject;
import javax.inject.Named;

import stackjava.com.cdidemo.qualifier.DatabaseType;
import stackjava.com.cdidemo.qualifier.TypeConnect;

@Named("daoUtils")
public class DAOUtils {

  @Inject
  @TypeConnect(type = DatabaseType.MY_SQL)
  private ConnectDatabase conn1;

  @Inject
  @TypeConnect(type = DatabaseType.DB2)
  private ConnectDatabase conn2;

  public void sync() {
    conn1.connect();
    conn2.connect();
    System.out.println("synchronize database...");
  }

}

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 daoUtils = (DAOUtils) bm.getReference(bean, DAOUtils.class, ctx);
    daoUtils.sync();
  }
}

Kết quả:

Connect MySQL database
Connect DB2 database
synchronize database...

Download code ví dụ tại đây

 

Java CDI Inject nhiều kiểu vào cùng một bean, annotation @Qualifier

References:

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

stackjava.com