IoC is a key component of our developments, in particular in the cloud to develop faster and behave properly depending the cloud vendor or environment. Let see how Fusion compares to the well-known Spring and CDI.

IoC

The *I*nversion *o*f *C*ontrol (IoC) is the simple concept to link objects between them from contracts and not require you to do the plumbing. Concretely you write My billing service needs a customer service and not My billing service uses the database customer service.

The impact? You can change the behavior of the services consuming your service as a dependency by plugging another implementation. In previous example, if you change of customer service to move to elasticsearch, the billing service still works.

Concretely in Java there are two main ways to do that:

  • A declarative way which is the most known solution (@Inject and friends),

  • The programmatic way (lookup and derivatives).

The counter part is to be able to define beans. Most of the time it is about declaring a class (potentially implementing the contract as an interface if the contract is not the class itself). But for 3rd parties, you need to be able to define a method as a factory of bean instances since you don’t control the class and don’t always want to wrap/decorate the 3rd parties to still integrate with the ecosystem of these libraries.

Lastly, a common piece of an IoC and *D*ependency *I*njection framework is to handle scopes, i.e. define when to create/destroy an instance. Common cases are per application (singleton), per request (take care it is NOT the servlet request in general), per session or per injection (each injection has its own instance).

in this post we will not discuss the qualifier notion which enables to remove the ambiguity between two beans of the same type.

Spring/Spring-Boot

Spring-Boot is likely the oldest and most used IoC framework in Java. it is backed by Pivotal and designed to be reflection/runtime (even if the recent GraalVM track enables to get AOT working, code stays runtime oriented).

Injections

In spring ecosystem, the injection can be handled with four main solutions:

  • @Autowired: the historical and default way to mark a field as injected,

  • @Inject: alias for @Autowired coming from the JSR330 (pseudo standard of injections but without defining much behavior actually),

  • Constructor injections, i.e. the constructor gets parameters injected from its signature simulating all parameters have @Autowired,

  • Programmatic lookups using the ApplicationContext or BeanFactory depending your case.

Here are the most common examples:

Spring field injection
public class BillingService {
    @Autowired
    private CustomerService service;
}
Spring constructor injection
public class BillingService {
    private final CustomerService service;

    public BillingService(final CustomerService service) {
        this.service = service;
    }
}

3rd party beans

To define a bean of a type you don’t declare you can use @Bean (generally in a @Configuration class):

Spring 3rd party
@Configuration
public class MyAppPlumbing {
    @Bean (1)
    public MyBackend ds() {
        return ...;
    }
}
1 Mark the method as declaring a bean factory, if the instance is AutoCloseable, close() will be called to destroy the instance.

Scopes

Scopes are mainly a way to request injections to be replaced by a proxy which will delegate to an instance depending of the context (ex: request).

It is mainly a matter of marking a bean (class or method) with a scope annotation or the generic @Scope annotation. Then the lookup of the actual instance will be delegated to some plumbing between the annotation and proxy.

Here is how to declare a bean request scope:

Spring scope
@RequestScope (1)
public class MyBean {}
1 Simply putting the scope annotation enables to mark the bean with this scope.

CDI

CDI is the standard inherited from JavaEE and now hosted at Eclipse under JakartaEE organisation. It intends to provide a portable and normalized way to do IoC and stands for *C*ontext and *D*ependency *I*njection.

It has three main runtimes:

  • light: which targets mainly GraalVM to be explicit,

  • full: which targets standalone applications or more generally any CDI application. This one inherit from light but has a runtime Extension mecanism to modify the application at startup. As of today it overlaps a lot with the light API which got added in last release but only this API defines when it is executed so it is more stable than light which is undefined as of today.

  • EE: integration in EE containers, it is mainly full flavor without the standalone container API.

Injections

In CDI ecosystem, the injection can be handled with two main solutions:

  • @Inject: similar to the spring @Autowired, it can be set on a field, constructor (to select the constructor to use) or a setter.

  • Programmatic lookups using the BeanManager or Instance.

Here are the most common examples:

CDI field injection
public class BillingService {
    @Inject
    private CustomerService service;
}
CDI constructor injection
public class BillingService {
    private final CustomerService service;

    @Inject
    public BillingService(final CustomerService service) {
        this.service = service;
    }
}

3rd party beans

To define a bean of a type you don’t declare you can use @Produces in any bean, note that comparing to spring you must define a @Disposes method if you need to cleanup the bean:

CDI 3rd party
@ApplicationScoped
public class MyAppPlumbing {
    @Produces (1)
    public MyBackend ds() {
        return ...;
    }

    public void releaseDs(@Disposes final MyBackend backend) { (2)
        ....
    }
}
1 Mark the method as declaring a bean factory,
2 Defines a callback to destroy the bean instance.

Scopes

In CDI, scopes are very similar to Spring. To define a request scope instance, just mark it as such for example:

CDI scope
@RequestScoped (1)
public class MyBean {}
1 Simply putting the scope annotation enables to mark the bean with this scope.
CDI has the notion of normal scopes (an instance is always the same in a single context) which require the beans to be proxyable (class non final with a no-arg constructor etc…​).

Fusion

Yupiik Fusion is very similar even if it intends to be very lightweight so you shouldn’t be lost. The key difference is that it is closer to dagger by generating the plumbing of the application at build time but keeping the capacity to reconfigure the wiring at runtime using modules.

Injections

In Fusion ecosystem, the injection can be handled with two main solutions:

  • @Injection: similar to the spring @Autowired, it can be set on a not private field.

  • Programmatic lookups using the RuntimeContainer.

Here are the most common examples:

Fusion field injection
public class BillingService {
    @Injection
    protected CustomerService service;
}
Fusion constructor injection
public class BillingService {
    private final CustomerService service;

    public BillingService(final CustomerService service) {
        this.service = service;
    }
}

3rd party beans

To define a bean of a type you don’t declare you can use @Bean in any bean, if the instance implements AutoCloseable it is automatically alled to destroy the instance:

CDI 3rd party
@DefaultScoped (1)
public class MyAppPlumbing {
    @Bean (2)
    public MyBackend ds() {
        return ...;
    }
}
1 Mark the enclosing class as being a bean (using default scoped as a marker for the compiler),
2 Defines the 3rd party bean.

Scopes

In Fusion scopes are annotations:

Fusion scope
@ApplicationScoped (1)
public class MyBean {}
1 Simply putting the scope annotation enables to mark the bean with this scope.
as of today, Fusion only handles @ApplicationScoped to define singletons and @DefaultScoped to mark a bean as being created per injection/lookup. Note that the application scope behaves close to CDI one by using a proxy and lazy instantiation of the underlying bean whereas Spring will use eager instantiation.

Conclusion

This post is a high level overview of three Java IoC. A lot more is interesting to compare like the facts:

  • Fusion generates all the code at build time and limits the runtime to the lookup resolution,

  • the resolution itself which is not the same for all three frameworks,

  • the Fusion ecosystem which is not only an IoC,

  • the way to tune the IoC when it starts with extensions/modules,

  • the integration more or less smooth with GraalVM to become native,

  • and much more!

To learn more, you can check the online documentation and the source code repository.

Enjoy!

From the same author:

In the same category: