EJB Interceptors Example
1. Introduction
This is an example of how to use the javax.interceptor.*
in an EJB.
Interceptors are used, as the name suggests, to intercept ejb methods calls using methods annotated with interceptor annotation (@AroundInvoke
, @AroundTimeout
, @PostConstruct
etc ).
An interceptor method is called by Ejb Container before ejb method call it is intercepting.
The Interceptors specification defines two kinds of interception points:
- business method interception, and
- lifecycle callback interception.
In addition, the EJB specification defines timeout method interception.
2. Create a new EJB Module
Open NetBeans IDE, choose File > New Project.
In the New Project wizard, expand the Java EE category and select EJB Module as shown in the figure below. Then click Next.
You have to specify the Project Name, the Project Name and the Project Location in the appropriate text fields and then click Next.
In the next window , add the JEE Server and select the JEE version and click Finish.
3. Create a new Session Bean
Go to File -> New File -> Enterprises JavaBeans -> Session Bean or
Right-click the EJB module project and choose New > Session Bean .
4. EJB Interceptors
4.1 Introduction
The EJB 3.0 spec defines the ability to apply custom made interceptors to the business methods of your beans.
4.2 Implementing interceptors
An interceptor is defined as a simple class where there is a single method annotated with @AroundInvoke
and life-cycle annotation . This method will be called on every business and life-cycle method call to the EJB .
SampleInterceptor.java
package org.netbeans.example; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.interceptor.AroundConstruct; import javax.interceptor.AroundInvoke; import javax.interceptor.InvocationContext; /** * * @author jGauravGupta */ public class SampleInterceptor { @PostConstruct public void init(InvocationContext context) throws Exception { System.out.println("SampleInterceptor > PostConstruct > init"); context.proceed(); } @AroundConstruct public Object construct(InvocationContext context) throws Exception { System.out.println("SampleInterceptor > construct"); return context.proceed(); } @AroundInvoke public Object invoke(InvocationContext context) throws Exception { System.out.println("SampleInterceptor > invoke"); return context.proceed(); } @PreDestroy public void destroy(InvocationContext context) throws Exception { System.out.println("SampleInterceptor > PreDestroy > destroy"); context.proceed(); } }
4.3 Binding an interceptor to a bean
Here is the EJB that will use the above Interceptor to intercept it’s methods using Interceptors
annotation.
@javax.interceptor.Interceptors
declares an ordered list of interceptors for a target class or method of a target class.
SampleBean.java
package org.netbeans.example; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.ejb.Stateless; import javax.ejb.LocalBean; import javax.interceptor.Interceptors; /** * * @author jGauravGupta */ @Stateless @LocalBean @Interceptors(SampleInterceptor.class) public class SampleBean { @PostConstruct public void init() { System.out.println("SampleBean > PostConstruct > init"); } public void test() { System.out.println("SampleBean > test"); } @PreDestroy public void destroy() { System.out.println("SampleBean > PreDestroy > destroy"); } }
4.4 Tester
Let’s create a simple auto startup Singleton Bean to test the desired functionality.
Tester.java
package org.netbeans.example; import javax.annotation.PostConstruct; import javax.ejb.EJB; import javax.ejb.Singleton; import javax.ejb.LocalBean; import javax.ejb.Startup; /** * * @author jGauravGupta */ @Singleton @LocalBean @Startup public class Tester { @EJB SampleBean sampleBean; @PostConstruct public void init() { sampleBean.test(); } }
4.5 Output
Verify the following output in NetBeans console :
Info: SampleInterceptor > construct Info: SampleInterceptor > PostConstruct > init Info: SampleBean > PostConstruct > init Info: SampleInterceptor > invoke Info: SampleBean > test Info: InterceptorExample was successfully deployed in 199 milliseconds. Info: SampleInterceptor > PreDestroy > destroy Info: SampleBean > PreDestroy > destroy Info: visiting unvisited references Info: visiting unvisited references Info: Portable JNDI names for EJB Tester: Info: Portable JNDI names for EJB SampleBean: Info: SampleInterceptor > construct Info: SampleInterceptor > PostConstruct > init Info: SampleBean > PostConstruct > init Info: SampleInterceptor > invoke Info: SampleBean > test Info: InterceptorExample was successfully deployed in 232 milliseconds.
4.6 Download the NetBeans Project
Download the NetBeans project of Interceptor tutorial:
You can download the full source code of this example here: InterceptorExample.zip
5. CDI Interceptors
5.1 Introduction
CDI Interceptors are pretty much the same as EJB interceptors, however since they are applied using a qualifier, you will at first define your interceptor qualifier, for example, here is a SampleBinding qualifier (which can be triggered by adding the @SampleBinding
annotation on your Beans):
5.2 Interceptor bindings
An interceptor binding type may be declared by specifying the @javax.interceptor.InterceptorBinding
meta-annotation.
Go to File -> New File -> Contexts and Dependency Injection > Interceptor Binding Type :
Type SampleBinding for the class name and org.netbeans.example for the package :
SampleBinding.java
package org.netbeans.example; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.Target; import javax.interceptor.InterceptorBinding; /** * * @author jGauravGupta */ @Inherited @InterceptorBinding @Retention(RUNTIME) @Target({METHOD, TYPE}) public @interface SampleBinding { boolean transaction() default false; }
Suppose we want to add some extra information to our @SampleBinding
annotation . CDI will use the value of transaction to choose between two different interceptors TransactionalInterceptor
and NonTransactionalInterceptor
.
5.3 Implementing interceptors
Now will code the Interceptor definition, which is annotated with the qualifier annotation (@SampleBinding
) as well as with the @Interceptor
annotation at the top of it.
Right-click on SampleBinding.java
editor -> Insert Code… -> Generate Interceptor :
TransactionalInterceptor.java
package org.netbeans.example; import javax.interceptor.AroundConstruct; import javax.interceptor.AroundInvoke; import javax.interceptor.Interceptor; import javax.interceptor.InvocationContext; /** * * @author jGauravGupta */ @SampleBinding(transaction = true) @Interceptor public class TransactionalInterceptor { @AroundConstruct public Object construct(InvocationContext context) throws Exception { System.out.println("TransactionalInterceptor > construct"); return context.proceed(); } @AroundInvoke public Object invoke(InvocationContext context) throws Exception { System.out.println("TransactionalInterceptor > invoke"); return context.proceed(); } }
NonTransactionalInterceptor.java
package org.netbeans.example; import javax.interceptor.AroundConstruct; import javax.interceptor.AroundInvoke; import javax.interceptor.Interceptor; import javax.interceptor.InvocationContext; /** * * @author jGauravGupta */ @SampleBinding(transaction = false) @Interceptor public class NonTransactionalInterceptor { @AroundConstruct public Object construct(InvocationContext context) throws Exception { System.out.println("NonTransactionalInterceptor > construct"); return context.proceed(); } @AroundInvoke public Object invoke(InvocationContext context) throws Exception { System.out.println("NonTransactionalInterceptor > invoke"); return context.proceed(); } }
5.4 Binding an interceptor to a bean
Now we can apply this annotation either at class level (and will intercept all method calls) or at method level, so it will intercept just that method call. Let’s apply it to the SampleBean
:
SampleBean.java
package org.netbeans.example; import javax.ejb.Stateless; import javax.ejb.LocalBean; /** * * @author jGauravGupta */ @Stateless @LocalBean @SampleBinding(transaction = true) public class SampleBean { public void test() { System.out.println("SampleBean > test"); } }
The @SampleBinding(transaction = true)
annotation applied at class level denotes that all the methods should be intercepted with TransactionalInterceptor
.
5.5 Enabling interceptors
By default, all interceptors are disabled. To enable the cdi interceptors , you need to declare it into your beans.xml file:
beans.xml
<?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" bean-discovery-mode="annotated"> <interceptors> <class>org.netbeans.example.TransactionalInterceptor</class> <class>org.netbeans.example.NonTransactionalInterceptor</class> </interceptors> </beans>
Those lines in beans.xml
not only “enable” the interceptors, but also define the “order of execution” of the interceptors.
5.6 Output
Verify the following output in NetBeans console :
Info: TransactionalInterceptor > construct Info: TransactionalInterceptor > invoke Info: SampleBean > test
5.7 Download the NetBeans Project
Download the NetBeans project of the CDI Interceptor tutorial:
You can download the full source code of this example here: CDI_InterceptorExample.zip