Spring 回退 bean 实现
Spring fallback bean implementation
我目前正在尝试配置 Spring Boot(使用 Java Annotations 和 ComponentScan) 对于以下场景:
场景
- 有一个接口
MyService
。
- 我想为
MyService
提供默认实现,我们称之为 MyDefaultService
。
- 如果组件扫描未检测到
MyService
的其他实现,Spring 应将 MyDefaultService
实例化为 "fallback"。
- 如果存在
MyService
的不同实现,比如说 MyCustomService
,那么那个 bean 应该 always 优先于 MyDefaultService
将依赖项自动装配到 MyService
时。在这方面,MyDefaultService
应该是 隐性 (而不是 @Primary
)。
- 理想情况下,不需要在
MyCustomService
上添加注释即可获得 "override" MyDefaultService
.
- 理想情况下,不需要明确实施的工厂或工厂方法。
问题
问题是:我需要如何注释 MyDefaultService
class 才能实现此目的?
到目前为止我尝试解决的问题
- 用
@ConditionalOnMissingBean(MyService.class)
注释 MyDefaultService
。没有工作,因为 MyDefaultService
从未使用过,即使 MyService
. 没有其他实现
- 有一个名为
@Primary
的注释解决了这个问题。但是,它需要驻留在 MyCustomService
上,一个 class,我尽量避免添加额外的注释。本质上,我需要 MyDefaultService
上 @Primary
的 inverse 注释。但是,我找不到这样的注释。
具体用例
我正在一个项目中开发一个服务层,另一个项目将在它之上实现一个 web UI 层。 UI 项目依赖于服务层项目。但是,对于在服务层实现的某些功能,我需要知道哪个用户当前在 Web 上下文中登录。所以我必须在服务层项目中为它定义一个服务接口,这样它就可以被UI项目实现。但是,为了在服务层项目中进行测试,我需要该接口的默认实现。此外,如果 UI 项目团队忘记实现此接口,应用程序不应崩溃,而是实例化回退 bean 并发出警告。
谢谢和亲切的问候,
艾伦
我建议写一个 FactoryBean
的实现来做到这一点。您的 FactoryBean
将扫描 bean 工厂以寻找实现 MyService
的 bean,如果它找到一个它 return 就是来自 getObject
的那个 bean。如果没有,那么它可以直接实例化 MyDefaultService
和 return 。然后你的工厂 bean 被注释为 @Primary
.
所以像这样的片段(伪代码):
public class MyServiceFactory implements FactoryBean<MyService> {
ListableBeanFactory beanFactory;
public MyService getObject() {
Map beans = beanFactory.getBeansOfType(MyService.class)
if (beans.isEmpty())
return new MyDefaultService(); // plus args, obviously
else
return get_some_bean_from_the_map
}
}
然后是
@Primary
@Bean
public MyServiceFactory MyServiceFactory() {
return new MyServiceFactory();
}
Spring 将自动处理工厂 bean(即它将使 MyService
对象像正常情况一样可用作注入 bean。
这个解决方案不需要任何特殊的魔法,而且它的工作原理非常明显。您还可以处理错误的情况,例如声明多个 MyService
个 bean。
我目前正在尝试配置 Spring Boot(使用 Java Annotations 和 ComponentScan) 对于以下场景:
场景
- 有一个接口
MyService
。 - 我想为
MyService
提供默认实现,我们称之为MyDefaultService
。 - 如果组件扫描未检测到
MyService
的其他实现,Spring 应将MyDefaultService
实例化为 "fallback"。 - 如果存在
MyService
的不同实现,比如说MyCustomService
,那么那个 bean 应该 always 优先于MyDefaultService
将依赖项自动装配到MyService
时。在这方面,MyDefaultService
应该是 隐性 (而不是@Primary
)。 - 理想情况下,不需要在
MyCustomService
上添加注释即可获得 "override"MyDefaultService
. - 理想情况下,不需要明确实施的工厂或工厂方法。
问题
问题是:我需要如何注释 MyDefaultService
class 才能实现此目的?
到目前为止我尝试解决的问题
- 用
@ConditionalOnMissingBean(MyService.class)
注释MyDefaultService
。没有工作,因为MyDefaultService
从未使用过,即使MyService
. 没有其他实现
- 有一个名为
@Primary
的注释解决了这个问题。但是,它需要驻留在MyCustomService
上,一个 class,我尽量避免添加额外的注释。本质上,我需要MyDefaultService
上@Primary
的 inverse 注释。但是,我找不到这样的注释。
具体用例
我正在一个项目中开发一个服务层,另一个项目将在它之上实现一个 web UI 层。 UI 项目依赖于服务层项目。但是,对于在服务层实现的某些功能,我需要知道哪个用户当前在 Web 上下文中登录。所以我必须在服务层项目中为它定义一个服务接口,这样它就可以被UI项目实现。但是,为了在服务层项目中进行测试,我需要该接口的默认实现。此外,如果 UI 项目团队忘记实现此接口,应用程序不应崩溃,而是实例化回退 bean 并发出警告。
谢谢和亲切的问候,
艾伦
我建议写一个 FactoryBean
的实现来做到这一点。您的 FactoryBean
将扫描 bean 工厂以寻找实现 MyService
的 bean,如果它找到一个它 return 就是来自 getObject
的那个 bean。如果没有,那么它可以直接实例化 MyDefaultService
和 return 。然后你的工厂 bean 被注释为 @Primary
.
所以像这样的片段(伪代码):
public class MyServiceFactory implements FactoryBean<MyService> {
ListableBeanFactory beanFactory;
public MyService getObject() {
Map beans = beanFactory.getBeansOfType(MyService.class)
if (beans.isEmpty())
return new MyDefaultService(); // plus args, obviously
else
return get_some_bean_from_the_map
}
}
然后是
@Primary
@Bean
public MyServiceFactory MyServiceFactory() {
return new MyServiceFactory();
}
Spring 将自动处理工厂 bean(即它将使 MyService
对象像正常情况一样可用作注入 bean。
这个解决方案不需要任何特殊的魔法,而且它的工作原理非常明显。您还可以处理错误的情况,例如声明多个 MyService
个 bean。