Skip to content

CDI Microservice Provider

Tomáš Livora edited this page Apr 5, 2017 · 6 revisions

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.

Content

  1. Usage
    1. Bean management
    2. Versioning
  2. Internals
    1. Microservice CDI Extension
    2. Microservice proxy
    3. Look-up strategy
      1. First-found-local
      2. Random-robin
      3. Round-robin
    4. Method handler

Usage

To be able to use this provider, you need to be familiar with CDI (Contexts and Dependency Injection).

Bean management

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.

Versioning

Internals

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.

Microservice CDI Extension

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.

Microservice proxy

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.

Look-up strategy

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;
...

First-Found-Local

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.

Round-Robin

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

Random-Robin

RandomRobinLookupStrategy is similar to RoundRobinLookupStrategy, but when the query returns multiple microservices,the result is picked randomly.

Method handler

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 to Integer.MAX_VALUE and HystrixMethodHandler has priority set to 0. 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();
    }
}