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
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ả:
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