DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • Magic of Aspects: How AOP Works in Spring
  • Adding Versatility to Java Logging Aspect
  • Introducing SmallRye LLM: Injecting Langchain4J AI Services
  • Injecting Implementations With Jakarta CDI Using Polymorphism

Trending

  • GitHub Copilot's New AI Coding Agent Saves Developers Time – And Requires Their Oversight
  • Rust, WASM, and Edge: Next-Level Performance
  • Enforcing Architecture With ArchUnit in Java
  • Monolith: The Good, The Bad and The Ugly
  1. DZone
  2. Coding
  3. Languages
  4. Simple Aspect Oriented Programming (AOP) using CDI in JavaEE

Simple Aspect Oriented Programming (AOP) using CDI in JavaEE

By 
Mohamed Sanaulla user avatar
Mohamed Sanaulla
·
Sep. 05, 14 · Interview
Likes (0)
Comment
Save
Tweet
Share
14.5K Views

Join the DZone community and get the full member experience.

Join For Free

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(){
      isauthorized();
      //execute business logic.
   }
}

public class myanotherservice{
  public servicemodel service1(){
    isauthorized():
    //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(
    id int not null auto_increment, 
    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();
                person.setid(rs.getstring("id"));
                person.setname(rs.getstring("name"));
                person.setplace(rs.getstring("place"));
                people.add(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();
                    person.setid(rs.getstring("id"));
                    person.setname(rs.getstring("name"));
                    person.setplace(rs.getstring("place"));
                    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 @interceptorbinding that 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;

@interceptorbinding
10
@retention(runtime)
11
@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;

@interceptor
@latencylogger
public class latencyloggerinterceptor implements serializable{
  
  @aroundinvoke
    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"
       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="all">
    
    <interceptors>
        <class>demo.latencyloggerinterceptor</class>
    </interceptors>
</beans>

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 {

  @inject
  peopledao peopledao;

  @latencylogger
  public list<person> getallpeople() throws sqlexception {
    return peopledao.getallpeople();
  }

  @latencylogger
  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 {

  @inject
  peopleservice peopleservice;

  @override
  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>
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <title>aop demo</title>
  </head>
  <body>
    <h1>hello world!</h1>
    <table>
      <tr>
        <th>id</th>
        <th>name</th>
        <th>place</th>
      </tr>
      <c:foreach items="${requestscope.people}" var="person">
        <tr>
          <td><c:out value="${person.id}"/></td>
          <td><c:out value="${person.name}"/></td>
          <td><c:out value="${person.place}"/></td>
        </tr>
      </c:foreach>
    </table>
    <br/>
    details for person with id=2
    <c:out value="name ${person.name} from ${person.place}" />
  </body>
</html>

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 :)


Aspect-oriented programming CDI Aspect (computer programming) code style

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

Opinions expressed by DZone contributors are their own.

Related

  • Magic of Aspects: How AOP Works in Spring
  • Adding Versatility to Java Logging Aspect
  • Introducing SmallRye LLM: Injecting Langchain4J AI Services
  • Injecting Implementations With Jakarta CDI Using Polymorphism

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!