pixel
pixel

Reputation: 10577

What is SpringBoot alternative to JavaEE CDI?

I know that JakartaEE (formely JavaEE) has support for CDI since JavaEE 6.

To my knowledge SpringBoot does not have CDI but only DI.

Does SpringBoot support CDI (Context and Dependency Injection) or offer some alternative to it?

Upvotes: 3

Views: 4416

Answers (2)

Adam Waldenberg
Adam Waldenberg

Reputation: 2321

The whole Spring Framework in itself is actually an alternative. Difference here is that it's not as cleanly seperated in Spring - instead its part of the intricacies of the Spring Framework.

The Spring Framework has an alternative for nearly every feature in CDI. For the sake of argument and completeness, we can do a comparison and discuss differences and similarities;

Managed objects

In CDI you would define an injectable or managed class in the following way:

@[ManagedBean / Named]
@[ApplicationScoped / Dependant / RequestScoped / Singleton / ViewScoped]
public class MyClass {
    @PostConstruct private void init() { ... }
    @PreDestroy private void destroy() { ... }
}

Springs equivalent to the same definition looks like this:

@[Bean / Controller / Component / Repository / Service]
public class MyClass {
    @PostConstruct private void init() { ... }
    @PreDestroy private void destroy() { ... }
}

Whenever a class is defined as a @Component or a @Bean in Spring, it can also take a scope:

@[Bean / Component]
@Scope([
    SCOPE_APPLICATION / SCOPE_PROTOTYPE / SCOPE_REQUEST / SCOPE_SESSION / 
    SCOPE_SINGLETON / "websocket"
])
public class MyClass { ... }

Just like with CDI, Spring is also extendable and can be extended with additional scopes by developers if they need special behavior.

With CDI we inject and let the framework inject managed objects by annotating a member with @Inject. The equivalent annotation for injecting managed objects in Spring is @Autowired.

Signals

When defining a signal in CDI, we would inject a member like:

@Inject
private Event<Payload> event;

We would then send a signal to all listeners by invoking event.fire(new Payload()) or event.fireAsync(new Payload()). An event listener (or observer, as they are called in CDI) would then be defined by adding a method like this one to a managed object:

public void onPayload(@Observes Payload event) { ... }

In a similar manner, signals in a Spring application are defined like this:

@Autowired
private ApplicationEventPublisher event;

In Spring, events are then fired by invoking event.publishEvent(new Payload()). Event listeners in Spring are defined slightly diffrently:

@Component
public class Observer {
    @EventListener public void onPayload(Payload payload) { ... }
}

Producers

In CDI, we can create a method that "produces" a specific object by defining a producer. These essentially act like factories. These objects can later be created by injecting them with @Inject. By default, producers are @Dependant, but they can also define a scope.

@RequestScoped
public class LoggerFactory {
    @Produces
    public Logger createLogger() {
        return new Logger();
    }
}

To do the very same thing in Spring, we would do something like this:

@Configuration
public class LoggerFactory {
    @Bean @Scope(SCOPE_REQUEST)
    public Logger createLogger() {
        return new Logger();
    }
}

Of course, rather than using @Inject, you would use @Autowired in Spring to inject instances of these objects.

Interceptors

Interceptors allow us to "modify" or "decorate" methods with custom behavior. In CDI, we typically first define an annotation. This annotation is then later used to decorate methods with our custom code:

@Target( { METHOD, TYPE } ) @Retention( RUNTIME )
public @interface MyInterceptor { }

We then define a behavior for that interceptor:

@Interceptor @MyInterceptor
public class MyInterceptorHandler {
    @AroundInvoke public Object interception(InvocationContext ctx) throws Exception {
        /* You can do something additional here ... */
        Object result = ctx.proceed();
        /* ... and/or here ... */

        return result;
    }
}

So here we can choose exactly where we want to insert extra code and when to proceed with the invocation of the decorated method. To decorate a method for interception you could do something like this:

@ApplicationScoped
public class MyService {
    @MyInterceptor public String operation(String str) {
        return str;
    }
}

In Spring its similar and different at the same time. Spring itself does not have anything like this specifically, but has instead added support for AspectJ into the framework. So to create a similar interceptor in Spring, you would do something like this:

@Aspect
public class MyInterceptorHandler {
    @Around("execution("*com.mycompany.project.MyService.*(..))")
    public Object interception(ProceedingJoinPoint jp) throws Throwable {
        /* You can do something additional here ... */
        Object result = jp.proceed();
        /* ... and/or here ... */

        return result;
    }
}

At this point we don't need to do anything more, because interception will be applied to all the methods of MyService, as specified by the @Around annotation.

Conclusion

So this post was a bit drawn out. But it does show some of the similarities and differences between CDI and Spring. Using this little how-to, you can, for the most common tasks, easily migrate to CDI if you know Spring and vice versa.

Upvotes: 17

Laird Nelson
Laird Nelson

Reputation: 16196

Spring is a single-vendor product. CDI is a multi-vendor standard implemented by several different companies and products (Weld, OpenWebBeans) that has been in Java EE since version 6 and Jakarta EE since version 8. Both Spring and CDI implement the JSR-330 specification, but beyond that have absolutely nothing to do with one another.

Upvotes: 1

Related Questions