Default Interception Service Implementation
In the hk2-extras module there is a default implementation of the InterceptionService which
uses annotations to determine what services are to be intercepted and which interceptors should
be used. This page describes this default implementation.
Indicating Services to be Intercepted
All services to be intercepted by this implementation must be annotated with the
Intercepted qualifier. The Intercepted qualifier may
only be placed on classes. Here is an example of a service that can used method or
constructor interception when using the default InterceptionService
implementation:
@Service
@Intercepted
public class MyService {
// Can be intercepted
@Inject
public MyService(ServiceLocator locator) {
}
// Can be intercepted
public boolean goEagles() {
return true;
}
}
Indicating Interceptors
A class that wishes to be used as a method or constructor interceptor must adhere to the
following rules:
Since MethodInterceptor and ConstructorInterceptor are API from
the AopAlliance, they are not naturally marked with Contract. Therefore it is often the case
when doing automatic analysis of contracts that the ContractsProvided annotation
must be used to ensure that the standard AopAlliance interface is included in the set of
contracts. Here is an example of a method interceptor:
@Service
@Interceptor
@ContractsProvided({MyMethodInterceptor.class, MethodInterceptor.class})
public class MyMethodInterceptor implements MethodInterceptor {
// ...
}
Here is an example of a constructor interceptor:
@Service
@Interceptor
@ContractsProvided({MyConstructorInterceptor.class, ConstructorInterceptor.class})
public class MyConstructorInterceptor implements ConstructorInterceptor {
// ...
}
Interception Bindings
We must still be able to associate intercepted things such as constructors and methods of intercepted services
with the specific interceptors. This is done by using the InterceptionBinder
annotation. The InterceptionBinder is placed on user defined annotations to indicate
that the annotation is meant to associate an interceptor and the thing to be intercepted.
For example, if the user has a security interceptor, they might define their annotation like this:
@Inherited
@InterceptionBinder
@Target({TYPE, METHOD, CONSTRUCTOR})
@Retention(RUNTIME)
@Documented
public @interface Secure {
}
They would then put that annotation both on the security interceptor like so:
@Service
@Interceptor
@ContractsProvided({ConstructorInterceptor.class, MethodInterceptor.class})
@Secure
public class SecurityInterceptor implements MethodInterceptor, ConstructorInterceptor {
// ...
}
Then any method or constructor on an intercepted service that needs to be secure
would add the @Secure annotation as well:
@Service
@Intercepted
public class KernelSanders {
@Secure
public KernelSanders() {
// Lets make some chicken!
}
@Secure
public String getSecretFormula() {
return secretFormula;
}
}
The user annotation that is marked with InterceptionBinder can
also be placed on the service that is intercepted in order to indicate that all
methods (and the construtor which hk2 will call) should be intercepted by interceptors
with matching annotations. For example if the user annotation is this:
@Inherited
@InterceptionBinder
@Target({TYPE, METHOD, CONSTRUCTOR})
@Retention(RUNTIME)
@Documented
public @interface Trace {
}
Then the intercepted service can put Trace at the class level to indicate that all
methods should be traced:
@Service
@Intercepted
@Trace
public class LoudService {
}
If there is a corresponding interceptor that is marked with the Trace annotation then all
methods and/or constructors of the LoudService will be traced.
Also, annotations marked with InterceptionBinder are transitive.
So services marked with the following annotation will invoke interceptors with both the
Secure and Trace annotations:
@Inherited
@InterceptionBinder
@Trace @Secure
@Target({TYPE, METHOD, CONSTRUCTOR})
@Retention(RUNTIME)
@Documented
public @interface SecurelyTraceable {
}
Interceptor Ordering and Customization
Normally interceptors will run in their natural HK2 ordering (based on Rank and serivce/locator id)
but sometimes it is convenient to re-order the interceptors based on some external configuration.
It may also be convenient to add or remove interceptors that will run with some method or
constructor. The default implementation of the interception service has defined its own plugin service
named the InterceptorOrderingService that allows users to add, modify
or remove the set of intereceptors that would normally be run on a method or constructor.
The methods of the InterceptorOrderingService are supplied with
the list of interceptors that would be run on the given Method or Constructor. The
implementations of those methods can either return the list as-is (or return null) or they can
return their own list with a set of interceptors that should be run instead (and in what order).
If there are more than one implementation of the InterceptorOrderingService
then all implementations are run in hk2 ranking order with the results of the previous service
being given to the next service. In this way chains of interceptor ordering modifiers can be used together.
Getting it all started
In order to enable the default implementation of the InterceptionService
you will need to use the enableDefaultInterceptorServiceImplementation method of
the ExtrasUtilities class. You will also need to include the hk2-extras module
on your classpath.