Interceptor Method Annotations
- javax.interceptor.AroundConstruct
Designates the method as an interceptor method that receives a callback after the target class is constructed. - javax.interceptor.AroundInvoke
Designates the method as an interceptor method. - javax.interceptor.AroundTimeout
Designates the method as a timeout interceptor for interposing on timeout method for enterprise bean timers. - javax.annotation.PostConstruct
Designates the method as an interceptor method for post-construct lifecycle events. - javax.annotation.PreDestroy
Designates the method as an interceptor method for pre-derstroy lifecycle events.
Interceptor classes have the same lifecycle as their associated target class.
Example
- Interceptor
This interceptor will be used to log each method calls and an execution time of it. On a previous post, we created an injectable Logger object and the injection is used in this example. A proceed method of the InvocationContext proceed to the next interceptor. If the interceptor is the last interceptor, it triggers the target class method.
@Interceptor public class LoggingInterceptor implements Serializable { @Inject private transient Logger logger; @AroundInvoke public Object logMethod(InvocationContext ict) throws Exception { long start = System.currentTimeMillis(); logger.info(" Entering " + ict.getTarget().getClass().getName() + " - " + ict.getMethod().getName()); try{ return ict.proceed(); }finally{ logger.info(" Exiting " + ict.getTarget().getClass().getName() + " - " + ict.getMethod().getName() + " Execution Time: " + (System.currentTimeMillis() - start) + "ms"); } } }
- Target class
I will use a simple Hello RESTful service, which is very same as one shown on a previous post. To use an interceptor in a target class, an @Interceptors(LoggingInterceptor.class) annotation is used. When you use more than one interceptor, you can use the annotation like this: @Interceptors({FirstInterceptor.class, SecondInterceptor.class})
@Interceptors(LoggingInterceptor.class) @Path("/hello") public class Hello { @Inject private Logger logger; @GET public String sayHello(){ logger.info("Hello World Logging!"); return"Hello RESTful world!"; } }
Let's run it on a TomEE maven plug in. Pom.xml is still same as shown on this post and this post.
mvn clean install tomee:run
- Result
Open a URL http://localhost:8080/demo/hello
Then, look at the console output. The second line is from the sayHello method in the target class and the first & the third line is from the interceptor method.
INFO [http-nio-8080-exec-2] demo.interceptor.LoggingInterceptor.logMethod Entering demo.rest.endpoint.Hello - sayHello INFO [http-nio-8080-exec-2] demo.rest.endpoint.Hello.sayHello Hello World Logging! INFO [http-nio-8080-exec-2] demo.interceptor.LoggingInterceptor.logMethod Exiting demo.rest.endpoint.Hello - sayHello Execution Time: 0ms
InterceptorBinding
Interceptor bindings are intermediate annotations can be used to associate an interceptor with target beans (with class level or method level).
@InterceptorBinding @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Logging { }
We can use this interceptor binding with the LoggingInterceptor shown above. Simply added the
@Logging @Interceptor public class LoggingInterceptor implements Serializable { @Inject private transient Logger logger; @AroundInvoke public Object logMethod(InvocationContext ict) throws Exception { long start = System.currentTimeMillis(); logger.info(" Entering " + ict.getTarget().getClass().getName() + " - " + ict.getMethod().getName()); try{ return ict.proceed(); }finally{ logger.info(" Exiting " + ict.getTarget().getClass().getName() + " - " + ict.getMethod().getName() + " Execution Time: " + (System.currentTimeMillis() - start) + "ms"); } } }
Then, interceptor classes need to be defined in the beans.xml file (shown on a previous post) with an <interceptors> element.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd" version="1.1" bean-discovery-mode="all"> <interceptors> <class>demo.interceptor.LoggingInterceptor</class> </interceptors> </beans>
After this, we can use the interceptor binding directly in target classes instead of an @Interceptors annotation. The logging result is same.
@Logging @Path("/hello") public class Hello { @Inject private Logger logger; @GET public String sayHello(){ logger.info("Hello World Logging!"); return"Hello RESTful world!"; } }
No comments:
Post a Comment