Code ví dụ Interceptor trong CDI Java, annotation @Interceptor

Code ví dụ Interceptor trong CDI Java, annotation @Interceptor

Interceptor trong CDI là một chức năng giống như AspectJ, cho phép lọc/chặn các method một cách độc lập mà không ảnh hưởng tới chương trình.

(Xem lại: AspectJ là gì? Spring AOP + AspectJ ví dụ với AspectJ)

Chức năng Interceptor rất hữu ích trong những trường hợp tiền xử lý, hậu xử lý các method, request.

Ví dụ cơ bản hay gặp nhất là chức năng viết log, ta không cần sửa đổi code chương trình, sử dụng Interceptor để thực hiện log các method như lúc trước khi bắt đầu method, lúc method được thực thi và lúc method kết thúc.

Code ví dụ Interceptor trong CDI

Ở ví dụ này mình sẽ thực hiện sử dụng interceptor để ghi log cho các method.

Gồm các bước sau:

  • Tạo annotation để binding interceptor
  • Tạo class cài đặt interceptor
  • Thêm annotation vào những nơi cần thực hiện interceptor/binding
  • Enable chức năng interceptor.\

Tạo maven project

Code ví dụ Interceptor trong CDI Java, annotation @Interceptor

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>

Tạo annotation để binding:

package stackjava.com.democdi.interceptors;

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.interceptor.InterceptorBinding;


@InterceptorBinding @Retention(RUNTIME) @Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface Logger {
}

Tạo class cài đặt interceptor:

package stackjava.com.democdi.interceptors;

import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;

@Interceptor
@Logger
public class Logged {

    @AroundInvoke
      public Object log(InvocationContext invocationCtx) throws Exception{
          long startTime = System.currentTimeMillis();
          System.out.println("Start method: " + invocationCtx.getMethod().getName());
          //execute the intercepted method and store the return value
          Object returnValue = invocationCtx.proceed();
          System.out.println("End method: " + invocationCtx.getMethod().getName());
          long endTime = System.currentTimeMillis();
          System.out.println(invocationCtx.getMethod().getName() +": " + (endTime-startTime)+"ms");
          return returnValue;
          
      }
}
  • Annotation @AroundInvoke được dùng để chỉ rõ hành động sẽ thực hiện khi method được interceptor thực thi. Nó tương đương với annotation @Before, @After… trong AspectJ

Đặt annotation vào những method cần interceptor:

package stackjava.com.democdi.interceptors;

import javax.inject.Named;

@Named("hello")
public class Hello {

  @Logger
  public void printHello() {
    System.out.println("Hello World!");
  }

  public void printOk() {
    System.out.println("Ok!");
  }
}
  • Ở đây mình đặt annotation @Logger vào trước method printHello(), khi method này được thực thi nó sẽ được lọc qua method log() của class Logged

Bật chức năng interceptor:

Mặc định, chức năng interceptor bị disabled, để enable nó chúng ta phải chỉ rõ class cài đặt interceptor trong thẻ của 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">

  <interceptors>
    <class>stackjava.com.democdi.interceptors.Logged</class>
  </interceptors>

</beans>

Demo:

package stackjava.com.democdi.interceptors;

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;

public class MainApp {
  
  @SuppressWarnings("unchecked")
  public static void main(String[] args) {
    Weld weld = new Weld();
    WeldContainer container = weld.initialize();
    BeanManager bm = container.getBeanManager();

    Bean<Hello> bean = (Bean<Hello>) bm.getBeans("hello").iterator().next();
    CreationalContext<Hello> ctx = bm.createCreationalContext(bean);
    Hello hello = (Hello) bm.getReference(bean, Hello.class, ctx);
    hello.printHello();
    System.out.println("----------------");
    hello.printOk();

  }

}

Kết quả:

Code ví dụ Interceptor trong CDI Java, annotation @Interceptor

So sánh CDI Interceptor với Spring AspectJ

Theo bản thân mình thấy thì 2 cái này nó thực hiện chức năng giống nhau, nên ta tùy theo môi trường để sử dụng.

Nếu bạn đang làm với Spring Framework thì Spring AspectJ là một lựa chọn tố, tuy nhiên nếu chỉ làm thuần với J2EE thì CDI Interceptor đáng để cân nhắc hơn.

 

Okay, done!

Thanks các bạn đã theo dõi bài viết!

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

Code ví dụ Interceptor trong CDI Java, annotation @Interceptor

References:

https://docs.oracle.com/javaee/6/tutorial/doc/gkhjx.html

 

stackjava.com