+

Search Tips   |   Advanced Search

EJB 3.x interceptors

An interceptor is a method that is automatically called when the business methods of an EJB are invoked or lifecycle events of an EJB occur.

There are three kinds of interceptor methods: business method interceptors, timeout method interceptors (which are new in EJB3.1), and lifecycle callback interceptors. Business method interceptors are invoked around the call to a business method. Timeout method interceptors are invoked around the call to an EJB timeout method. Lifecycle callback interceptors are called around one of the PostConstruct, PreDestroy, PrePassivate, or PostActivate lifecycle events. For each interceptor type, an individual class can only declare one interceptor method. However, each class in a class hierarchy can declare an interceptor method for each interceptor type. If an interceptor method in a subclass overrides the same method in a super-class, only the method in the subclass might be invoked.

Interceptor methods are permitted to access and call all resources and components that the associated method is allowed to call. Additionally, interceptor methods execute with the same transaction and security context as the associated method. Except for singleton session beans, lifecycle interceptor methods are executed with local transaction containment (LTC).

We can declare interceptor methods directly in the EJB class or in a separate interceptor class. To declare interceptor methods in a separate class, we must bind the interceptor class to the EJB using either an annotation or XML. Declare interceptors using the annotation:

@Interceptors({ClassInterceptor1.class, ClassInterceptor2.class})
public class TestBean { /* ... */ }

@Interceptors({ClassInterceptor1.class})
public class TestBean2 {
	@Interceptors({MethodInterceptor1.class, MethodInterceptor2.class})
	public void businessMethod() { /* ... */ }
}

Declare interceptors using the deployment descriptor:

  <assembly-descriptor>
    <interceptor-binding>
      <ejb-name>TestBean</ejb-name>
      <interceptor-class>ClassInterceptor1</interceptor-class>
      <interceptor-class>ClassInterceptor2</interceptor-class>
    </interceptor-binding>

    <interceptor-binding>
      <ejb-name>TestBean2</ejb-name>
      <interceptor-class>ClassInterceptor1</interceptor-class>
    </interceptor-binding>

    <interceptor-binding>
      <ejb-name>TestBean2</ejb-name>
      <interceptor-class>MethodInterceptor1</interceptor-class>
      <interceptor-class>MethodInterceptor2</interceptor-class>
      <method>
        <method-name>businessMethod</method-name>
      </method>
    </interceptor-binding>
  </assembly-descriptor>

We can exclude class-level interceptors from a method using either the ExcludeClassInterceptors annotation or the exclude-class-interceptors element in the deployment descriptor. Use the following example to exclude the interceptor, ClassInterceptor, from the method, businessMethod.

@Interceptors({ClassInterceptor1.class})
public class TestBean2 {
	@ExcludeClassInterceptors
	public void businessMethod() { /* ... */ }

	public void businessMethodWithClassInterceptor1() { /* ... */
}

Use the following example to exclude the interceptor from the method using the deployment descriptor:

  <assembly-descriptor>
    <interceptor-binding>
      <ejb-name>TestBean2</ejb-name>
      <exclude-class-interceptors>true</exclude-class-interceptors>
      <method>
        <method-name>businessMethod</method-name>
      </method>
    </interceptor-binding>
  </assembly-descriptor>

Interceptor methods can have public, protected, package private, or private visibility. Interceptor methods must not be final or static. Business method interceptors and timeout method interceptors must have a return type of java.lang.Object, a single parameter of javax.interceptor.InvocationContext, and a single throws clause type of java.lang.Exception. All lifecycle interceptors must have a return type of void and must not have a throws clause. Lifecycle interceptors declared directly on the EJB class must not have parameters; lifecycle interceptors declared on an EJB superclass or on an interceptor class must have a single parameter of javax.interceptor.InvocationContext. Timeout interceptor methods and lifecycle interceptor methods must not throw application exceptions.

Use the InvocationContext parameter of an interceptor method to get information about the method being invoked. The getTarget method returns the bean instance being invoked. The getTimer method is applicable to timeout method interceptors only, and it returns the timer being executed. The getMethod method returns the business interface method being used invoked. The getParameters method returns the parameters being passed to the business method, and the setParameters method allows the parameters to be modified. The getContextData method returns the data association with the method being invoked. Finally, the proceed method invokes either the next interceptor or the target method.

We can declare interceptor methods using either annotations or XML. To declare an interceptor method using an annotation, place the appropriate AroundInvoke, AroundTimeout, PostConstruct, PreDestroy, PrePassivate, or PostActivate annotation on the interceptor method. Declare a business method interceptor, a timeout method interceptor, and a PostConstruct lifecycle interceptor method on an EJB class using annotations.

@Interceptors({ClassInterceptor.class})
public class TestBean {
	@PostConstruct
	private void beanPostConstruct() { /* ... */ }

	@AroundInvoke
	protected Object beanAroundInvoke(InvocationContext ic) throws Exception {
		return ic.proceed();
	}

        @AroundTimeout
        protected Object beanAroundTimeout(InvocationContext ic) throws Exception {
		return ic.proceed();
        }
}

Declare the same interceptor methods on an interceptor class.

public class ClassInterceptor {
	@PostConstruct
	private void interceptorPostConstruct(InvocationContext ic) {
		try {
			ic.proceed();
		} catch (Exception ex) { /* ... */ }
	}

	@AroundInvoke
	protected Object interceptorAroundInvoke(InvocationContext ic) throws Exception {
		return ic.proceed();
	}

	@AroundTimeout
	protected Object interceptorAroundTimeout(InvocationContext ic) throws Exception {
		return ic.proceed();
	}
}

Alternatively, we can declare an interceptor method in the deployment descriptor with the around-invoke, around-timeout, post-construct, pre-destroy, pre-passivate, and post-activate elements. Declare a business method interceptor, a timeout method interceptor, and a PostConstruct lifecycle interceptor method on an EJB class and an interceptor class using the deployment descriptor.

  <enterprise-beans>
    <session>
      <ejb-name>TestBean</ejb-name>
      <around-invoke>
        <method-name>beanAroundInvoke</method-name>
      </around-invoke>
      <around-timeout>
        <method-name>beanAroundTimeout</method-name>
      </around-timeout>
      <post-construct>
        <lifecycle-callback-method>beanPostConstruct</lifecycle-callback-method>
      </post-construct>
    </session>
  </enterprise-beans>

  <interceptors>
    <interceptor>
      <interceptor-class>ClassInterceptor</interceptor-class>
      <around-invoke>
        <method-name>interceptorAroundInvoke</method-name>
      </around-invoke>
      <around-timeout>
        <method-name>interceptorAroundTimeout</method-name>
      </around-timeout>
      <post-construct>
        <lifecycle-callback-method>interceptorPostConstruct</lifecycle-callback-method>
      </post-construct>
    </interceptor>
  </interceptors>

  <assembly-descriptor>
    <interceptor-binding>
      <ejb-name>TestBean</ejb-name>
      <interceptor-class>ClassInterceptor</interceptor-class>
    </interceptor-binding>
  </assembly-descriptor>

We can also declare interceptor methods on super-classes. Declare a PostActivate interceptor on a bean super-class using annotations:

public class TestBean extends BeanSuperClass { /* ... */ }

public class BeanSuperClass {
	@PostActivate
	private void beanSuperClassPostActivate(InterceptorContext ic) {
		try {
			ic.proceed();
		} catch (Exception ex) { /* ... */ }
	}
}

Declare the same interceptor method on a superclass of an interceptor class using annotations:

public class ClassInterceptor extends InterceptorSuperClass { /* ... */ }

public class InterceptorSuperClass {
	@PostActivate
	private void interceptorSuperClassPostActivate(InterceptorContext ic) {
		try {
			ic.proceed();
		} catch (Exception ex) { /* ... */ }
	}
}

We can also declare the same interceptor methods using the deployment descriptor. Declare an interceptor method on the superclasses of a bean and interceptor class:

<enterprise-beans>
  <session>
    <ejb-name>TestBean</ejb-name>
    <post-activate>
      <class>BeanSuperClass</class>
	 <lifecycle-callback-method>beanSuperClassPostActivate</lifecycle-callback-method>
    </post-activate>
  </session>
 </enterprise-beans>

 <interceptors>
   <interceptor>
    <interceptor-class>ClassInterceptor</interceptor-class>
    <post-activate>
      <class>InterceptorSuperClass</class>
	 <lifecycle-callback-method>interceptorSuperClassPostActivate</lifecycle-callback-method>
    </post-activate>
   </interceptor>
 </interceptors>

 <assembly-descriptor>
   <interceptor-binding>
     <ejb-name>TestBean</ejb-name>
     <interceptor-class>ClassInterceptor</interceptor-class>
   </interceptor-binding>
 </assembly-descriptor>

We can declare default interceptors that apply to all session and message-driven beans in a module. Default interceptors can only be declared in the deployment descriptor, and they are specified using an ejb-name of "*". Declare a default interceptor.

  <assembly-descriptor>
    <interceptor-binding>
      <ejb-name>*</ejb-name>
      <interceptor-class>DefaultInterceptor</interceptor-class>
    </interceptor-binding>
  </assembly-descriptor>

We can exclude default interceptors from a specific class or method using either the ExcludeDefaultInterceptors annotation or the exclude-default-interceptors element in XML. Use the following examples to exclude default interceptors using the annotation:

@ExcludeDefaultInterceptors
public class TestBean { /* ... */ }

public class TestBean2 {
	@ExcludeDefaultInterceptors
	public void businessMethod() { /* ... */ }
}

Use the following example to excludes default interceptors using the deployment descriptor:

  <assembly-descriptor>
    <interceptor-binding>
      <ejb-name>TestBean</ejb-name>
      <exclude-default-interceptors>true</exclude-default-interceptors>
    </interceptor-binding>

    <interceptor-binding>
      <ejb-name>TestBean2</ejb-name>
      <exclude-default-interceptors>true</exclude-default-interceptors>
      <method>
        <method-name>businessMethod</method-name>
      </method>
    </interceptor-binding>
  </assembly-descriptor>

When interceptors are invoked for a method, default interceptor classes are invoked first, class-level interceptors are invoked next, and interceptors methods from the EJB class are invoked last. For a single interceptor class hierarchy, interceptor methods are always invoked on the most general super-class first. The default and class-level interceptor classes are invoked in the order specified in the deployment descriptor or the Interceptors annotation. We can override this ordering by specifying the complete list of default and class-level interceptors in the interceptor-order element in the deployment descriptor.

  <assembly-descriptor>
    <interceptor-binding>
      <ejb-name>TestBean</ejb-name>
      <!--
        The default ordering would be:
	  1. DefaultInterceptor
	  2. ClassInterceptor1
	  3. ClassInterceptor2

	The following stanza overrides the default ordering.
      -->
      <interceptor-order>
        <interceptor-class>ClassInterceptor2</interceptor-class>
	<interceptor-class>DefaultInterceptor</interceptor-class>
	<interceptor-class>ClassInterceptor1</interceptor-class>
      </interceptor-order>
    </interceptor-binding>
  </assembly-descriptor>


Related:

  • Enterprise beans
  • Developing enterprise beans
  • Enterprise bean development best practices