Over a million developers have joined DZone.

Simple Aspect Oriented Programming (AOP) using CDI in JavaEE

DZone's Guide to

Simple Aspect Oriented Programming (AOP) using CDI in JavaEE

· Java Zone
Free Resource

Learn how to troubleshoot and diagnose some of the most common performance issues in Java today. Brought to you in partnership with AppDynamics.

We write service APIs which cater to certain business logic. There are few cross-cutting concerns that cover all service APIs like Security, Logging, Auditing, Measuring Latencies and so on. This is a repetitive non-business code which can be reused among other methods. One way to reuse is to move these repetitive code into its own methods and invoke them in the service APIs somethings like:

public class MyService{
   public ServiceModel service1(){
      //execute business logic.

public class MyAnotherService{
  public ServiceModel service1(){
    //execute business logic. 

The above approach will work but not without creating code noise, mixing cross-cutting concerns with the business logic. There is another approach to solve the above requirements which is by using Aspect and this approach is called Aspect Oriented Programming (AOP). There are a different ways you can make use of AOP – by using Spring AOP, JavaEE AOP. In this example I Will try to use AOP using CDI in Java EE applications. To explain this I have picked a very simple example of building a web application to fetch few records from Database and display in the browser.

Creating the Data access layer

The table structure is:

create table people(
    name varchar(100) NOT NULL,
    place varchar(100),
    primary key(id));

Lets create a Model class to hold a person information

package demo.model;
public class Person{
  private String id;
  private String name;
  private String place;
  public String getId(){ return id; } 
  public String setId(String id) { this.id = id;}
  public String getName(){ return name; } 
  public String setName(String name) { this.name = name;}
  public String getPlace(){ return place; } 
  public String setPlace(String place) { this.place = place;}

Lets create a Data Access Object which exposes two methods -

  1. to fetch the details of all the people
  2. to fetch the details of one person of given id
package demo.dao;

import demo.common.DatabaseConnectionManager;
import demo.model.Person;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

public class PeopleDAO {

    public List<Person> getAllPeople() throws SQLException {
        String SQL = "SELECT * FROM people";
        Connection conn = DatabaseConnectionManager.getConnection();
        List<Person> people = new ArrayList<>();
        try (Statement statement = conn.createStatement();
                ResultSet rs = statement.executeQuery(SQL)) {
            while (rs.next()) {
                Person person = new Person();
        return people;

    public Person getPerson(String id) throws SQLException {
        String SQL = "SELECT * FROM people WHERE id = ?";
        Connection conn = DatabaseConnectionManager.getConnection();
        try (PreparedStatement ps = conn.prepareStatement(SQL)) {
            ps.setString(1, id);
            try (ResultSet rs = ps.executeQuery()) {
                if (rs.next()) {
                    Person person = new Person();
                    return person;

        return null;

You can use your own approach to get a new Connection. In the above code I have created a static utility that returns me the same connection.

Creating Interceptors

Creating Interceptors involves 2 steps:

  1. Create Interceptor binding which creates an annotation annotated with @InterceptorBindingthat is used to bind the interceptor code and the target code which needs to be intercepted.
  2. Create a class annotated with @Interceptor which contains the interceptor code. It would contain methods annotated with @AroundInvoke, different lifecycle annotations,@AroundTimeout and others.

Lets create an Interceptor binding by name @LatencyLogger

package demo; 

import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.*;
import static java.lang.annotation.ElementType.*;
import javax.interceptor.InterceptorBinding;

@Target({METHOD, TYPE})
public @interface LatencyLogger {


Now we need to create the Interceptor code which is annotated with @Interceptor and also annotated with the Interceptor binding we created above i.e @LatencyLogger:

package demo;
import java.io.Serializable;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;

public class LatencyLoggerInterceptor implements Serializable{
    public Object computeLatency(InvocationContext invocationCtx) throws Exception{
        long startTime = System.currentTimeMillis();
        //execute the intercepted method and store the return value
        Object returnValue = invocationCtx.proceed();
        long endTime = System.currentTimeMillis();
        System.out.println("Latency of " + invocationCtx.getMethod().getName() +": " + (endTime-startTime)+"ms");
        return returnValue;

There are two interesting things in the above code:

  1. use of @AroundInvoke
  2. parameter of type InvocationContext passed to the method

@AroundInvoke designates the method as an interceptor method. An Interceptor class can have only ONE method annotated with this annotation. When ever a target method is intercepted, its context is passed to the interceptor. Using the InvocationContext one can get the method details, the parameters passed to the method.

We need to declare the above Interceptor in the WEB-INF/beans.xml file

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"

Creating Service APIs annotated with Interceptors

We have already created the Interceptor binding and the interceptor which gets executed. Now lets create the Service APIs and then annotate them with the Interceptor binding

 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
package demo.service;

import demo.LatencyLogger;
import demo.dao.PeopleDAO;
import demo.model.Person;
import java.sql.SQLException;
import java.util.List;
import javax.inject.Inject;

public class PeopleService {

  PeopleDAO peopleDAO;

  public List<Person> getAllPeople() throws SQLException {
    return peopleDAO.getAllPeople();

  public Person getPerson(String id) throws SQLException {
    return peopleDAO.getPerson(id);


We have annotated the service methods with the Interceptor binding @LatencyLogger. The other way would be to annotate at the class level which would then apply the annotation to all the methods of the class. Another thing to notice is the @Inject annotation that injects the instance i.e injects the dependency into the class.

Next is to wire up the Controller and View to show the data. The controller is the servlet and view is a plain JSP using JSTL tags.

 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
package demo;

import demo.model.Person;
import demo.service.PeopleService;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "AOPDemo", urlPatterns = {"/AOPDemo"})
public class AOPDemoServlet extends HttpServlet {

  PeopleService peopleService;

  public void doGet(HttpServletRequest request, HttpServletResponse response)
          throws ServletException, IOException {
    try {
      List<Person> people = peopleService.getAllPeople();
      Person person = peopleService.getPerson("2");
      request.setAttribute("people", people);
      request.setAttribute("person", person);
      getServletContext().getRequestDispatcher("/index.jsp").forward(request, response);
    } catch (SQLException ex) {
      Logger.getLogger(AOPDemoServlet.class.getName()).log(Level.SEVERE, null, ex);

The above servlet is available at http://localhost:8080/ /AOPDemo. It fetches the data and redirects to the view to display the same. Note that the Service has also been injected using @Inject annotation. If the dependencies are not injected and instead created using  new then the Interceptors will not work. This is an important point which I realised while building this sample.

The JSP to render the data would be

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" 
           uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>AOP Demo</title>
    <h1>Hello World!</h1>
      <c:forEach items="${requestScope.people}" var="person">
          <td><c:out value="${person.id}"/></td>
          <td><c:out value="${person.name}"/></td>
          <td><c:out value="${person.place}"/></td>
    Details for person with id=2
    <c:out value="Name ${person.name} from ${person.place}" />

With this you would have built a very simple app using Interceptors. Thanks for reading and staying with me till this end. Please share your queries/feedback as comments. And also share this article among your friends :)

Understand the needs and benefits around implementing the right monitoring solution for a growing containerized market. Brought to you in partnership with AppDynamics.


Published at DZone with permission of Mohamed Sanaulla, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.


Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.


{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}