JavaEECDI的SpringBoot替代品是什么?
我知道 JakartaEE(以前称为 JavaEE)从 JavaEE 6 开始就支持 CDI。
据我所知,SpringBoot 没有 CDI,只有 DI。
SpringBoot 是否支持 CDI(上下文和依赖注入)或提供一些替代方案?
回答
整个 Spring Framework 本身实际上是一个替代方案。这里的不同之处在于它在 Spring 中没有完全分离——而是它是 Spring 框架错综复杂的一部分。
Spring Framework 为 CDI 中的几乎所有功能提供了替代方案。为了论证和完整性,我们可以做一个比较,讨论异同;
管理对象
在 CDI 中,您可以通过以下方式定义可注入或托管类:
@[ManagedBean / Named]
@[ApplicationScoped / Dependant / RequestScoped / Singleton / ViewScoped]
public class MyClass {
@PostConstruct private void init() { ... }
@PreDestroy private void destroy() { ... }
}
与相同定义等效的弹簧如下所示:
@[Bean / Controller / Component / Repository / Service]
public class MyClass {
@PostConstruct private void init() { ... }
@PreDestroy private void destroy() { ... }
}
每当一个类在 Spring 中被定义为 a@Component或 a@Bean时,它也可以采用一个范围:
@[Bean / Component]
@Scope([
SCOPE_APPLICATION / SCOPE_PROTOTYPE / SCOPE_REQUEST / SCOPE_SESSION /
SCOPE_SINGLETON / "websocket"
])
public class MyClass { ... }
就像 CDI 一样,Spring 也是可扩展的,如果需要特殊行为,开发人员可以使用额外的范围进行扩展。
使用 CDI,我们注入并让框架通过使用@Inject. 在 Spring 中注入托管对象的等效注解是@Autowired.
信号
在 CDI 中定义信号时,我们会注入一个成员,如:
@Inject
private Event<Payload> event;
然后,我们将通过调用event.fire(new Payload())或向所有侦听器发送信号event.fireAsync(new Payload())。然后将通过将这样的方法添加到托管对象来定义事件侦听器(或观察者,因为它们在 CDI 中被调用):
public void onPayload(@Observes Payload event) { ... }
以类似的方式,Spring 应用程序中的信号定义如下:
@Autowired
private ApplicationEventPublisher event;
在 Spring 中,然后通过调用event.publishEvent(new Payload()). Spring 中的事件侦听器定义略有不同:
@Component
public class Observer {
@EventListener public void onPayload(Payload payload) { ... }
}
生产者
在 CDI 中,我们可以通过定义生产者来创建一个“生产”特定对象的方法。这些基本上就像工厂一样。这些对象稍后可以通过注入它们来创建@Inject。默认情况下,生产者是@Dependant,但他们也可以定义范围。
@RequestScoped
public class LoggerFactory {
@Produces
public Logger createLogger() {
return new Logger();
}
}
为了在 Spring 中做同样的事情,我们会做这样的事情:
@Configuration
public class LoggerFactory {
@Bean @Scope(SCOPE_REQUEST)
public Logger createLogger() {
return new Logger();
}
}
当然,不是使用 ,而是在 Spring 中@Inject使用@Autowired来注入这些对象的实例。
拦截器
拦截器允许我们使用自定义行为“修改”或“装饰”方法。在 CDI 中,我们通常首先定义一个注解。这个注解随后被用来装饰我们的自定义代码的方法:
@Target( { METHOD, TYPE } ) @Retention( RUNTIME )
public @interface MyInterceptor { }
然后我们为该拦截器定义一个行为:
@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;
}
}
所以在这里我们可以准确地选择我们想要插入额外代码的位置以及何时继续调用装饰方法。要装饰拦截方法,您可以执行以下操作:
@ApplicationScoped
public class MyService {
@MyInterceptor public String operation(String str) {
return str;
}
}
在 Spring 中,它既相似又不同。Spring 本身并没有专门的类似功能,而是在框架中添加了对 AspectJ 的支持。因此,要在 Spring 中创建类似的拦截器,您可以执行以下操作:
@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;
}
}
此时我们不需要再做任何事情,因为拦截将应用于 的所有方法MyService,如@Around注释所指定。
结论
所以这篇文章有点拖沓。但它确实显示了 CDI 和 Spring 之间的一些异同。如果您了解 Spring,那么使用这个小指南,对于最常见的任务,您可以轻松迁移到 CDI,反之亦然。