Yupiik Fusion Injections
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 Inversion of Control (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 Dependency Injection 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).
TIP
|
in this post we will not discuss the |
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
orBeanFactory
depending your case.
Here are the most common examples:
public class BillingService {
@Autowired
private CustomerService service;
}
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):
@Configuration
public class MyAppPlumbing {
@Bean (1)
public MyBackend ds() {
return ...;
}
}
-
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:
@RequestScope (1)
public class MyBean {}
- 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 Context and Dependency Injection.
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
orInstance
.
Here are the most common examples:
public class BillingService {
@Inject
private CustomerService service;
}
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:
@ApplicationScoped
public class MyAppPlumbing {
@Produces (1)
public MyBackend ds() {
return ...;
}
public void releaseDs(@Disposes final MyBackend backend) { (2)
....
}
}
- Mark the method as declaring a bean factory,
- 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:
@RequestScoped (1)
public class MyBean {}
- Simply putting the scope annotation enables to mark the bean with this scope.
IMPORTANT
|
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:
public class BillingService {
@Injection
protected CustomerService service;
}
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:
@DefaultScoped (1)
public class MyAppPlumbing {
@Bean (2)
public MyBackend ds() {
return ...;
}
}
- Mark the enclosing class as being a bean (using default scoped as a marker for the compiler),
- Defines the 3rd party bean.
Scopes
In Fusion scopes are annotations:
@ApplicationScoped (1)
public class MyBean {}
- Simply putting the scope annotation enables to mark the bean with this scope.
IMPORTANT
|
as of today, Fusion only handles |
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: