Implementing the interceptor

Let's consider the example that we wrote earlier, where we created a person identity. Let's say we want to invoke some functionality around this identity creation function and that we don't necessarily want to mix this logic with the existing business function.

For instance, let's say we want to add audit functionality, which is a common cross-cutting concern. We can use interceptors to write a function to add audit messages, which will be invoked around the execution of the business function. We use the @Interceptors annotation to do this and then we can provide one or more interceptors for common application concerns:

@Stateless
@Interceptors(AuditInterceptor.class)
class App {
@Inject
private lateinit var identityCreator: IdentityCreator
@Inject
private lateinit var identityRepository: IdentityRepository

fun createIdentity(inputData: InputData): Identity {
val person = identityCreator.createPerson(inputData)
identityRepository.store(person)
return person
}
}

We will create an AuditInterceptor class in the interceptor package that is annotated with the @Interceptor annotation.

This interceptor will specify a handle function that is annotated with @AroundInvoke. The @AroundInvoke annotation declares the handle() function to be invoked around our business functionality.

By injecting the InvocationContext, we can simply use the context.proceed() function to proceed with our business functionality, as follows:

@Interceptor
public class AuditInterceptor {

@AroundInvoke
fun handle(context: InvocationContext){
context.proceed()
}
}

When the createIdentity() function is called, the handler function will be invoked by intercepting the invocation of the createIdentity() function call.

We can now include a CDI-managed bean, namely the Auditor. This class has a single audit() function that simply prints a message to the console once the function has been invoked:

class Auditor {
fun audit(message: String) {
println(message)
}
}

Let's inject the Auditor bean in the AuditInterceptor class and call the audit() function from handle():

@Interceptor
class AuditInterceptor {
@Inject
private lateinit var auditor: Auditor

fun handle(context: InvocationContext) {
auditor.audit("message")
context.proceed()
}
}

Now, the interceptor's handle() function has been invoked around the business logic of creating a person.

We could also use a context object to get some more information about the invocation intercepted, for example, arguments with which the function is invoked. An example code is shown here:
@Interceptor
class AuditInterceptor {
@Inject
private lateinit var auditor: Auditor

fun handle(context: InvocationContext) {
auditor.audit("message")
context.parameters.forEach { param -> println(param) }
context.proceed()
}
}

This section has shown how we can intercept some logic in our application without binding too much of the intercepting logic to the business code. The @Interceptors annotation controls whether the interceptor is invoked. This is not tightly bound to the business logic.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset