-
Notifications
You must be signed in to change notification settings - Fork 11
CDI Microservice Provider
CDI Microservice Provider is one of the most important components of SilverWare since it provides an easy way to manage and connect different microservices. It allows developers to use CDI in their applications and uses Weld SE as the underlying CDI container.
To be able to use this provider, you need to be familiar with CDI (Contexts and Dependency Injection).
If you want CDI container to manage your microservices, you will have to annotate them with @Microservice annotation. This way your microservice will become a managed bean with microservice scope (read Internals for more details).
@Microservice
public class MyService {
...
}
Such microservices can then be injected into others using @MicroserviceReference qualifier.
...
@Inject
@MicroserviceReference
private MyService myService;
...
Do not forget to put an empty beans.xml
file to META-INF
folder in your project resources to active CDI in your project.
Otherwise, your microservices will not be discovered by SilverWare.
You can use any CDI mechanisms when working with your microservices — alternatives, qualifiers, specializations, etc.
The following paragraphs describe how CDI Microservice Provider works under the hood. Although it is not completely necessary to know these things if you just want to use this provider for simple use cases, it is highly recommended to read this part in order to fully understand what SilverWare does with your microservices in the background. You may also find this information useful if you want to alter the default behavior.
SilverWare implements its own CDI extension which takes care of all @MicroserviceScoped beans. This scope is automatically assigned to every bean with @Microservice annotation and means that such a bean can be discovered both locally and from other instances of SilverWare in clustered setup.
All microservice beans are scanned by this extension and a new proxy bean is created for every injection point that has unique qualifiers and contains @MicroserviceReference qualifier as well. This proxy bean is then added to the CDI container as a new bean and takes care of creating a unique proxy for each injection point where a microservice is injected.
As mentioned earlier, microservice proxies are what get injected into all injection points with @MicroserviceReference qualifier instead of the actual microservice bean. This allows SilverWare to look up a microservice dynamically at the time it is really needed.
When a microservice method is called on this proxy, it will first go through a chain of method handlers where the last one will try to look up an instance of this service and then invoke the method on it.
Microservice proxies can use various strategies to look up microservices. It is possible to adjust lookup strategy for injection point by specifying @InvocationPolicy.
...
@Inject
@MicroserviceReference
@InvocationPolicy(lookupStrategy = RoundRobinLookupStrategy.class)
private MyService myService;
...
FirstFoundLocalLookupStrategy is the fastest strategy with a minimal footprint which can look up only local microservices and always returns the frst found microservice. This implementation is used by default.
RoundRobinLookupStrategy looks up the microservices from both remote and local ProvidingSilverService
instances and in case multiple microservices are matching the query, it chooses the microservices in a cyclic order
RandomRobinLookupStrategy is similar to RoundRobinLookupStrategy, but when the query returns multiple microservices,the result is picked randomly.
SilverWare provides a way to alter microservice method calls.
When a microservice method is called, a chain of method handlers ordered by their priorities is executed.
Unless it is prevented by other method handlers, DefaultMethodHandler
is always executed as the last one and invokes a method on an actual instance of a microservice.
You can implement your own method handler by extending MicroserviceMethodHandler
class. SilverWare will automatically find it and use it. To make it work, you need to follow these rules:
- Set the priority by adding @Priority annotation.
The value selection is completely up to you.
Note that
DefaultMethodHandler
has priority set toInteger.MAX_VALUE
andHystrixMethodHandler
has priority set to0
. If you do not specify priority, the default value (100
) will be used. If two method handlers have the same priority, their execution order will be undefined. - Provide a public constructor with a single parameter of type
MicroserviceMethodHandler
. This is the next method handler which should be executed after yours. - Implement
invoke
method. You can do basically anything in this method but you should eventually call the same method on the next method handler. - Implement
getProxyBean
method and return the proxy bean from the next method handler. You can use this proxy bean to get any additional information about the microservice being called. - Implement
getInjectionPoint
method and return the injection point from the next method handler. You can use this injection point to get any additional information about the field where the microservice is injected.
@Priority(42)
public class MyMethodHandler extends MicroserviceMethodHandler {
private final MicroserviceMethodHandler methodHandler;
public MyMethodHandler(final MicroserviceMethodHandler methodHandler) {
this.methodHandler = methodHandler;
}
@Override
public Object invoke(final Method method, final Object... args) throws Exception {
// do something
return methodHandler.invoke(method, args);
}
@Override
public MicroserviceProxyBean getProxyBean() {
return methodHandler.getProxyBean();
}
@Override
public InjectionPoint getInjectionPoint() {
return methodHandler.getInjectionPoint();
}
}