Difference between interceptors and decorators

In general, a decorator is used to add new functionality or modify existing functionality. It uses composition as an alternative to inheritance. Decorators often provide additional APIs (methods) that are not available in the decorated classes.

On the other hand, AOP (e.g. an interceptor) is used to enhance existing behavior. It does not add additional APIs and generally does not modify existing functionality. It is triggered by invocation of existing functionality and responds by taking some action; but the existing functionality as well as the existing API remain unchanged.

I am not familiar with the JEE implementations, so they may have blurred the lines between these two patterns. Important points to compare would be,

  • Can @Interceptor introduce new methods or only execute around existing methods?
  • Can @Interceptor override existing methods or only append additional behavior?
  • Can @Decorator be applied across packages & class hierarchies, or is it constrained by one of these?

In addition to functional differences between the two patterns, it may also be interesting to consider potential performance differences. I would expect @Interceptor to be considerably slower, since it needs to examine method calls at runtime, whereas @Decorator invocations can be resolved at compile time.


Decorator

One difference would be, as your example shows it, with decorator you usually write 1 decorator per 1 decorated class/interface.

Decorator example

interface Worker {
    void work();
}

class Decorated implements Worker {

    public void work() {

    }
}

class DecoratorByInheritance extends Decorated {

    public void work() {
        // pre
        super.work();
        // post
    }
}

class DecoratorByComposition implements Worker {

    Worker decorated;

    DecoratorByComposition(Worker decorated) {
        this.decorated = decorated;
    }

    public void work() {
        // pre
        this.decorated.work();
        // post
    }
}

Interceptor

With interceptors, which are part of the AOP concept, you write 1 interceptor for a bunch of classes / methods, e.g. you intercept all DAO methods and make sure a transaction is open before the invocation and closed after it.

Interceptor example

Declare a pointcut (what to match), here you match any method from the MyDao class that starts with insert, has any arguments and any return type.

@Pointcut("execution(* com.example.dao.MyDao.insert*(..))")
public void insertPointcut() {
}

Then you declare an around advice which references the pointcut

@Around(value = "com.example.SystemArchitecture.insertPointcut()")
public void interceptMethod(ProceedingJoinPoint pjp) {
        // do pre-work
        Object retVal = pjp.proceed();
        // do post work
        return retVal;
    }
}

Interceptors are more flexible but imagine you change the method name, if you use a decorator, you'll probably get a compiler error, with interceptors, it will just not match and not execute your 'around' logic.


Decorators very similar to interceptors with two interesting differences:

  1. A decorator must implement the interface it is decorating (and yet can be abstract, so it does not have to implement the methods)

  2. A decorator can have a reference to the object it decorates. It is done through injection

Ref: https://blog.frankel.ch/cdi-an-overview-part-2