Dynamic lookups

Another great feature of the CDI is to be able to control a lazy instantiation or resolution of a bean. This is done with the Provider<?> and Instance<?> APIs. Instance is a Provider allowing you to resolve a bean at runtime. Provider is an instance wrapper allowing you to decide when to instantiate the underlying instance.

Take a look at the following code snippet:

@ApplicationScoped
public class DynamicInstance {
@Inject
private Provider<MyService> myServiceProvider;

@Inject
private Instance<MyService> myServices;

public MyService currentService() {
return myServiceProvider.get(); <1>
}

public MyService newService(final Annotation qualifier) {
return myServices.select(qualifier).get(); <2>
}
}

Let's look at the underlying mechanism of the preceding code snippet:

  • Calling Provider.get() will trigger the creation of an underlying instance (MyService here). It delays the instantiation of the injection or makes the instantiation conditional. Note that it depends on the scope of the bean and that a normal scoped bean won't benefit much from this use.
  • Calling Instance.select(...) will make the bean definition more specific based on the injection point. In this case, we start from a bean type (MyService) with the implicit @Default qualifier and replace the implicit qualifier with the one passed as the parameter. Then, we resolve the bean and get its instance. This is useful for switching the implementation dynamically and conditionally.

Since an Instance is a Provider, the implementations share the same code for both. This means their performances will be the same.

Now the question is, what is the cost of using a programmatic lookup versus a plain injection? Is it more expensive or not? In terms of implementation, the code is quite comparable, it has to resolve the bean to instantiate and then instantiate it so that we are very close to an injection. We will ignore the small differences that do not impact the performance much. One issue here is its use: if you get a Provider injected and resolve it for each use, you will then increase a lot of the time spent on resolving and instantiating versus just using an already resolved and created instance.