STACKJAVA

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.

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

}

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...");
  }

}

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.

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...");
  }

}

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.

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

}
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