Back

Explore Courses Blog Tutorials Interview Questions
0 votes
2 views
in Java by (7k points)

I am interested in AOP. In every single case, they consist of lofty theory, vague UML models, and order of abstraction that are way too high-up for my liking.

Here is my understanding of AOP theory:

  1. Cross-cutting concerns such as logging, Authenticating, Synchronizing, Validating, Exception Handling, etc. become highly coupled in non-AOP systems as they are used universally by almost every component/module in the codebase.

  2. AOP defines aspects that abstract these cross-cutting concerns with the use of join points, advice, and pointcuts.

    1. Advice- The actual code implementing the cross-cutting concern.

    2. Join Point - An event that is triggered in non-AOP code that causes a particular aspect’s advice to be executed.

    3. Pointcut - Essentially, a mapping of join points to advice execution

  3. All the aspects are modularized into components and registered with an AspectWeaver. When non-AOP/POJO code comes across a join point, AspectWeaer “weaves” the mapped advice around the non-AOP code:
     

public class LoggingAspect

{

    // ...

    public void log(String msg) { ... }

}

public class ExceptionHandlingAspect

{

    // ..

    public void handle(Exception exc) { ... }

}

public class NonAOPCode

{

    // ...

    @LoggingAspect @ExceptionHandlingAspect

    public void foo()

    {

        // do some stuff...

    }

}

// Now in the driver

public static int main void(String[] args)

{

    NonAOPCode nonAOP = new NonAOPCode();

    nonAOP.foo();

}

// The AspectWeaver *magically* might weave in method calls so main now becomes:

{

    NonAOPCode nonAOP = new NonAOPCode();

    log(someMsg);

    nonAOP.foo();

    handle(someExc);

}


 

My Questions are: Is my understanding of Java-based AOP on target, or way off, and why? How could one correctly use annotations to implement aspects, advice, join points, pointcuts and this so-called aspect weaver?

1 Answer

0 votes
by (13.1k points)

Let us imagine that you want to log the time taken by some annotated methods using a @LogExecTime annotation.

I first create an annotation LogExecTime:
 

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)

public @interface LogExecTime {

}

Then I define an aspect:

@Component  // For Spring AOP

@Aspect

public class LogTimeAspect {

    @Around(value = "@annotation(annotation)")

    public Object LogExecutionTime(final ProceedingJoinPoint joinPoint, final LogExecTime annotation) throws Throwable {

        final long startMillis = System.currentTimeMillis();

        try {

            System.out.println("Starting timed operation");

            final Object retVal = joinPoint.proceed();

            return retVal;

        } finally {

            final long duration = System.currentTimeMillis() - startMillis;

            System.out.println("Call to " + joinPoint.getSignature() + " took " + duration + " ms");

        }

    }

}

I create a class annotated with LogExecTime:
 

@Component

public class Operator {

    @LogExecTime

    public void operate() throws InterruptedException {

        System.out.println("Performing operation");

        Thread.sleep(1000);

    }

}

And a main using Spring AOP:
 

public class SpringMain {

    public static void main(String[] args) throws InterruptedException {

        ApplicationContext context = new GenericXmlApplicationContext("applicationContext.xml");

        final Operator bean = context.getBean(Operator.class);

        bean.operate();

    }

}

If I run this class I am getting the following output on stdout:
 

Starting timed operation

Performing operation

Call to void testaop.Operator.Operate() took 1044 ms

As I did use Spring AOP rather than AspectJ weaver, the process is occurring at the run time using proxy mechanisms. So the .class files are left untouched. For instance, if I debug this program and put a breakpoint in operating you’ll see how Spring has performed the process.

As Spring AOP implementation is non-intrusive and uses the spring mechanisms you need to add the @component annotation and create the object using Spring context rather than plain new.

AspectJ on the other side will change the .class files. I tried this project with AspectJ and decompiled the Operator class with jad. This lead to:

public void operate()

    throws InterruptedException

{

    JoinPoint joinpoint = Factory.makeJP(ajc$tjp_0, this, this);

    operate_aroundBody1$advice(this, joinpoint, LogTimeAspect.aspectOf(), (ProceedingJoinPoint)joinpoint, (LogExecTime)(ajc$anno$0 == null && (ajc$anno$0 = testaop/Operator.getDeclaredMethod("operate", new Class[0]).getAnnotation(testaop/LogExecTime)) == null ? ajc$anno$0 : ajc$anno$0));

}

private static final void operate_aroundBody0(Operator ajc$this, JoinPoint joinpoint)

{

    System.out.println("Performing operation");

    Thread.sleep(1000L);

}

private static final Object operate_aroundBody1$advice(Operator ajc$this, JoinPoint thisJoinPoint, LogTimeAspect ajc$aspectInstance, ProceedingJoinPoint joinPoint, LogExecTime annotation)

{

    long startMillis = System.currentTimeMillis();

    Object obj;

    System.out.println("Starting timed operation");

    ProceedingJoinPoint proceedingjoinpoint = joinPoint;

    operate_aroundBody0(ajc$this, proceedingjoinpoint);

    Object retVal = null;

    obj = retVal;

    long duration = System.currentTimeMillis() - startMillis;

    System.out.println((new StringBuilder("Call to ")).append(joinPoint.getSignature()).append(" took ").append(duration).append(" ms").toString());

    return obj;

    Exception exception;

    exception;

    long duration = System.currentTimeMillis() - startMillis;

    System.out.println((new StringBuilder("Call to ")).append(joinPoint.getSignature()).append(" took ").append(duration).append(" ms").toString());

    throw exception;

}

private static void ajc$preClinit()

{

    Factory factory = new Factory("Operator.java", testaop/Operator);

    ajc$tjp_0 = factory.makeSJP("method-execution", factory.makeMethodSig("1", "operate", "testaop.Operator", "", "", "java.lang.InterruptedException", "void"), 5);

}

private static final org.aspectj.lang.JoinPoint.StaticPart ajc$tjp_0; /* synthetic field */

private static Annotation ajc$anno$0; /* synthetic field */

static 

{

    ajc$preClinit();

}

Want to learn Java? Check out the Core Java certification from Intellipaat.

Related questions

Browse Categories

...