英文:
Java Spring - enforce no bean inheritance
问题
首先,一些代码:
interface Foo {
void bar();
}
@Configuration
class FooConfig {
@Bean
public Foo foo() { return new MagicFoo(); }
class MagicFoo implements Foo { ... }
}
@Component
class FooImpl implements Foo {
public void bar() { }
}
@Component
class BarImpl {
final Foo foo;
public BarImpl(Foo foo) { this.foo = foo; }
}
在这个例子中,当实例化BarImpl
时,Spring框架将查找与Foo
匹配的bean,并优先选择由FooConfig
定义的bean(即MagicFoo
),而不是实现类FooImpl
。
我的问题是:是否有任何方法可以配置此代码,以便仅对与接口直接匹配的bean(例如Foo
),而不是任何实现类(例如FooImpl
)可用于特定接口依赖项?也就是说,是否可以通过某种方式配置Spring,以特殊的方式处理此类Foo
依赖项。
在这样的配置中,如果我移除了FooConfig
,尝试实例化BarImpl
时会出现错误,因为找不到合适的bean,即使存在FooImpl
的bean。换句话说,在这种期望的配置情况下,开发人员被迫明确地为已确定的接口定义bean,而不是将实现类标记为bean。
英文:
First, some code:
interface Foo {
void bar();
}
@Configuration
class FooConfig {
@Bean
public Foo foo() { return new MagicFoo(); }
class MagicFoo implements Foo { ... }
}
@Component
class FooImpl implements Foo {
public void bar() { }
}
@Component
class BarImpl {
final Foo foo;
public BarImpl(Foo foo) { this.foo = foo; }
}
As this example stands, when BarImpl
is instantiated, the Spring framework will look for a bean matching Foo
and prefer the bean defined by FooConfig
(i.e. the MagicFoo
) over the implementing-class FooImpl
.
My question is: is there any way to configure this code so that ONLY beans directly matching the interface (e.g. Foo
), and not any implementing classes (e.g. FooImpl
) are acceptable for a particular interface dependency? I.e. somehow configure Spring to treat Foo
dependencies in this special way.
In such a configuration, if I removed FooConfig
, I would get an error trying to instantiate BarImpl
because no suitable bean can be found, even though a bean for FooImpl
is available. In other words, with this desired configuration in place, the developer is forced to explicitly define beans for the identified interface instead of labeling implementing classes as beans.
答案1
得分: 2
如果您有多个实现了Foo
接口的bean,它们都可以作为类型为Foo
的参数进行自动装配的候选项。
您无法区分由@Bean
创建的bean和由@Component
创建的bean。
但是,您可以使用@Qualifier
进行隔离/分离它们。
@Configuration
class FooConfig {
@Bean
@Qualifier("ABC")
public Foo foo() { return new MagicFoo(); }
class MagicFoo implements Foo { ... }
}
@Component
@Qualifier("XYZ")
class FooImpl implements Foo {
public void bar() { }
}
@Component
class BarImpl {
final Foo foo;
public BarImpl(@Qualifier("ABC") Foo foo) { this.foo = foo; }
}
现在,参数只能由@Bean
创建的bean进行自动装配,因为这是唯一具有正确限定符的bean。
英文:
If you have multiple beans implementing Foo
, they are all candidates for autowiring a parameter of type Foo
.
You cannot distinguish between beans created by @Bean
vs beans created by @Component
.
You can however use @Qualifier
to isolate/separate them.
@Configuration
class FooConfig {
@Bean
@Qualifier("ABC")
public Foo foo() { return new MagicFoo(); }
class MagicFoo implements Foo { ... }
}
@Component
@Qualifier("XYZ")
class FooImpl implements Foo {
public void bar() { }
}
@Component
class BarImpl {
final Foo foo;
public BarImpl(@Qualifier("ABC") Foo foo) { this.foo = foo; }
}
The parameter can now only be autowired by the @Bean
created bean, because that is the only one with the correct qualifier.
答案2
得分: 0
在这一点上,我使用了以下设置来实现所需的行为:
- 我为不应作为特殊接口的 bean 使用的实现创建了一个注解。(例如
@ActvityImplementation
)- 这些特殊接口还有一个关联的注解来识别它们。(例如
@ActivityInterface
)
- 这些特殊接口还有一个关联的注解来识别它们。(例如
- 我有一个配置类,它引入了所有用
@ActivityImplementation
注解标记的 bean。- 参考链接:https://stackoverflow.com/a/48633041/2288986
- 配置类会反射每个实现 bean,以提取带有
@ActivityInterface
注解的接口。 - 对于每个实现 bean,我会查询 Spring 应用程序上下下文以查找与该接口匹配的 bean,并检查返回 bean 的类型。
- 如果返回的 bean 与实现类型匹配(而不是预期的“magic”类型),我会抛出错误。
这个逻辑确保我(以及使用该框架的其他人)不会忘记配置“magic”接口实现。当“magic”实现存在时,它是返回的接口 bean。当“magic”实现不存在时,Spring 会回退到实现 bean,从而触发错误。
英文:
At this point I've accomplished the desired behavior with the following setup:
- I created an annotation for the implementations that should not be used as beans for the special interfaces. (e.g.
@ActvityImplementation
)- The special interfaces also have an associated annotation that identifies them. (e.g.
@ActivityInterface
)
- The special interfaces also have an associated annotation that identifies them. (e.g.
- I have a configuration class that pulls in all the beans annotated with the
@ActivityImplementation
annotation. - The configuration class reflects on each implementation bean to extract the interface with the
@ActivityInterface
annotation. - For each implementation bean, I query the Spring application context for a bean matching the interface and check the type of the returned bean.
- If the returned bean matches the implementation type (as opposed to the intended "magic" type) I throw an error.
This logic ensures that I (and anyone else using the framework) cannot forget to configure the "magic" interface implementation. When the "magic" implementation is present, it is the bean returned for the interface. When the "magic" implementation is not present, Spring falls back to the implementation bean, which then triggers the error.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论