Wednesday, March 16, 2011

AOP (Aspect Oriented Programming) and EJB 3: Interceptors

An AOP system allows the separation of crosscutting concerns into their own modules. These modules are then applied across the relevant cross section of application code, such as the beginning of a method call.

EJB 3 supports AOP-like functionality by providing the ability to intercept business methods and lifecycle callbacks. EJB 3 interceptors are object that are automatically triggered when an EJB method is called. They do not provide all the functionality that a full-scale AOP package such as AspectJ offers but are easier to use.
These interceptors are called at the beginning of the bean method and when the method returns and it can inspect the return value or any exception thrown by the method.
Interceptors can be applied both on session beans and message driven beans.
Interceptors could be used for logging purposes or for any other purpose such as transaction or security informations.
In my application I created a logging interceptor that is called every time a user calls the login bean and I print in my business interceptor the username of the user.
This is the method that is called every time a user press the login button and calls the login bean. This method is annotated with the AroundInvoke metadata annotation. We can take the parameters passed to the method called by using the InvocationContext object and his getParameters() method. As you can see I got the Account parameter from the first position of the parameters array because I know that the first parameter that I passed to the authentication method is the Account object. 
After the logging of the user in this method I move on with the real method invocation using the method proceed() from the InvocationContext object.
Beyond these methods, the InvocationContext object has other interesting methods: the getTarget() method retrieves the bean instance of the intercepted method, the getMethod() retrieves the method name intercepted. We just saw the getParameters() method, there is also the setParameters that allows us to modify any parameter passed to the method intercepted. 
The getContextData() method allows us to share data, name-value pairs, between interceptors and retrieve these data in the interceptors chain. 
In the business method interceptor you can throw or handle checked and runtime exceptions. If an exception is thrown before the method is called, then the intercepted method will not be called at all. 

It is also possible to create interceptor lifecycle callback methods that intercept the lifecycle transition of the bean registered for the interceptor. These methods cannot throw checked exceptions and have to invoke the proceed() method of the InvocationContext at the end of the method to proceed the chain of interceptor lifecycle callback methods or the bean lifecycle callback method. In the next picture I show you mi entire Interceptor class: 



To register an interceptor to be called every time a bean's method is called we have to specify it in the bean class:


This is the annotation to be used for an interceptor on level class: it means that for every method called on my LoginBean class my interceptor CheckUserLogin will be called and the method annotated with the AroundInvoke annotation is executed. If we want this interceptor to be called for only one method in our bean we can move this annotation before the method signature. 
There could be three levels of interceptors: default, class level and method level. The default level interceptors will be called first, then the class level and finally the method level interceptors. 
In the @Interceptors annotation there could be a list of different interceptors and these are called in the order they appear on the list.  If we want to exclude a level of interceptors to be called for a given method or a class we could use the annotation @ExcludeDefaultInterceptors for both class and method level or @ExcludeClassInterceptors for the method we want to exclude these.

No comments:

Post a Comment