Are there any differences between interceptors and decorators in Java? Strictly speaking, can I implementing things with decorators which are not possible with interceptors and vice versa?
Except the problem that I would have to examine the method name to add method-specific behavior in an interceptor:
Interceptor:
@Nice
@Interceptor
public class NiceGreeterInterceptor {
@AroundInvoke
public Object decorate(InvocationContext ic) throws Exception {
Method method = ic.getMethod();
String methodName = method.getName();
Object result = ic.proceed();
if (methodName.equals("greet")) {
return "NEW " + result;
}
}
}
Decorator:
@Decorator
public class GreeterDecorator implements Greeter {
@Inject
@Any
@Delegate
private Greeter greeter;
@Override
public String greet() {
return "NEW " + greeter.greet();
}
}
Or is it legitimate to say that I can reproduce all the behavior of decorators with interceptors but it is more comfortable to use decorators?
An interceptor is a method that is automatically called when the business methods of an Enterprise JavaBeans (EJB) are invoked or lifecycle events of an EJB occur. There are three kinds of interceptor methods: business method interceptors, timeout method interceptors (which are new in EJB3.
Decorator Method is a Structural Design Pattern which allows you to dynamically attach new behaviors to objects without changing their implementation by placing these objects inside the wrapper objects that contains the behaviors.
In the field of software development, an interceptor pattern is a software design pattern that is used when software systems or frameworks want to offer a way to change, or augment, their usual processing cycle.
Decorator patterns allow a user to add new functionality to an existing object without altering its structure. So, there is no change to the original class. The decorator design pattern is a structural pattern, which provides a wrapper to the existing class.
One difference would be, as your example shows it, with decorator you usually write 1 decorator per 1 decorated class/interface.
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
}
}
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.
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.
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,
@Interceptor
introduce new methods or only execute around existing methods?@Interceptor
override existing methods or only append additional behavior?@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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With