Interceptor module is inspired from JavaEE/JakartaEE interceptor API but adapted to OSGi services.
It enables to proxy any service and execute code around the service methods.
Dependencies
<dependency>
<groupId>org.apache.karaf.services</groupId>
<artifactId>org.apache.karaf.services.interceptor.api</artifactId>
</dependency>
Defining an interceptor
An interceptor is simply an OSGi service marked with @Interceptor
and having an interceptor binding which is nothing more than an annotation marked with @InterceptorBinding
.
Here is a binding:
@Target({TYPE, METHOD})
@Retention(RUNTIME)
@InterceptorBinding
public @interface Suffix {
}
And here is an associated interceptor:
@Suffix
@Interceptor
@Component(service = SuffixingInterceptor.class)
public class SuffixingInterceptor {
// ...
}
Tip
|
the examples are using SCR but there is no requirement to do so, you can do it with context.registerService() as well.
|
For the interceptor to do something, you must define an @AroundInvoke
method which will intercept method calls in intercepted services.
It must takes a single parameter of type InvocationContext
:
@AroundInvoke
public Object around(final InvocationContext context) throws Exception {
return context.proceed() + "(suffixed)";
}
Using interceptors
Assuming you have an interceptor library (it is commong for transversal concerns like security, auditing, tracing, metrics, etc…), you can enable the interceptor usages with these few steps:
-
Ensure you register your service as an OSGi service,
-
Mark the service with
@EnableInterceptors
, -
Mark the class or method with the interceptor bindings you want
Tip
|
if you put a binding on a class is it available for all methods and is called after method level interceptors. |
As an example speaks better than 1000 words, here is a service using our previous suffixing interceptor:
@EnableInterceptors
@Component(service = InterceptedService.class)
public class InterceptedService {
@Suffix
public String doStuff(final String value) {
return "'" + value + "'";
}
}
You can notice that it is equivalent to the following example which just moved the interceptor at class level:
@Suffix
@EnableInterceptors
@Component(service = InterceptedService.class)
public class InterceptedService {
public String doStuff(final String value) {
return "'" + value + "'";
}
}
Proxying implementation
If possible, the proxying will use java.lang.reflect.Proxy
but if there is a class to proxy and not only interfaces, asm
must be available for the proxy to suceed to be created.