英文:
when there are some classes which may not exist, how should I manage them in an XxxAutoConfiguration?
问题
<dependency>
<groupId>com.example</groupId>
<artifactId>A</artifactId> // 它提供了 AFactory.class
<version>1</version>
<option>true</option>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>B</artifactId> // 它提供了 BFactory.class
<version>1</version>
<option>true</option>
<scope>provided</scope>
</dependency>
在我的初始项目中,我将编写一个 XxxAutoConfiguration
,该配置将使用 AFactory 或 BFactory。
我尝试过:
@Configuration
public class XxxAutoConfiguration {
private AFactory aFactory;
private BFactory bFactory;
@Autowired(required = false)
public void setAFactory(AFactory aFactory) {
this.aFactory = aFactory;
}
@Autowired(required = false)
public void setBFactory(BFactory bFactory) {
this.bFactory = bFactory;
}
@Bean
public Something something(){
if(aFactory != null){
return new Something(aFactory);
}else if(bFactory != null){
return new Something(bFactory);
}else{
throw new IllegalStateException();
}
}
}
但是它无法正常工作。
我知道我可以分别编写三个 AutoConfiguration,分别使用 @ConditionalOnBean(AFactory.class)
、@ConditionalOnBean(BFactory.class)
和 @ConditionalOnMissingBean(....)
来解决问题,但这远非优雅... 你有没有什么好的解决方案?非常感谢。
英文:
<dependency>
<groupId>com.example</groupId>
<artifactId>A</artifactId> // it provide AFactory.class
<version>1</version>
<option>true</option>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>B</artifactId> // it provide BFactory.class
<version>1</version>
<option>true</option>
<scope>provided</scope>
</dependency>
In my starter project, I will write a XxxAutoConfiguration
that uses AFactory or BFactory.
I've tried:
@Configuration
public class XxxAutoConfiguration {
private AFactory aFactory;
private BFactory bfactory;
@Autowired(required = false)
public void setaFactory(AFactory aFactory) {
this.aFactory = aFactory;
}
@Autowired(required = false)
public void setBfactory(BFactory bfactory) {
this.bfactory = bfactory;
}
@Bean
public Something something(){
if(aFactory != null){
return new Something(aFactory);
}else if(bfactory != null){
return new Something(bfactory);
}else{
throw new IllegalStateException();
}
}
}
but it doesn't work.
I know I can write three AutoConfiguration respectively with @ConditionalOnBean(AFactory.class)
, @ConditionalOnBean(BFactory.class)
and @ConditionalOnMissingBean(....)
to solve the problem, but it's
far from elegant... do you have any good solution? Thanks a lot.
答案1
得分: 0
在运行时使用可能不存在于类路径上的类来编写代码并不是一个好主意。编写代码以使其不引发 NoClassDefFoundError
是麻烦的。
标准的 Spring Boot 方法可以在 DataSourceConfiguration
的源代码中看到。
在你的情况下,你可以这样做:
abstract class XxxAutoConfiguration {
@Configuration
@ConditionalOnBean(AFactory.class)
@ConditionalOnMissingBean(Something.class)
@AutoConfigureOrder(1) // 首先尝试 AFactory
static class ASomething {
private AFactory aFactory;
@Autowired
void setaFactory(AFactory aFactory) {
this.aFactory = aFactory;
}
@Bean
Something something() {
return new Something(this.aFactory);
}
}
@Configuration
@ConditionalOnBean(BFactory.class)
@ConditionalOnMissingBean(Something.class)
@AutoConfigureOrder(2) // 其次尝试 BFactory
static class BSomething {
@Bean
Something something(BFactory bFactory) {
return new Something(bFactory);
}
}
}
如你所见,你可以使用 @Autowired
或者使用参数来实现,两种方式都应该可以工作。
如果类路径上同时存在 AFactory
和 BFactory
,你可以使用 @AutoConfigureOrder
来指定哪个胜出,就像这里展示的一样。还有其他更复杂的 @ConditionalXxx
注解。
XxxAutoConfiguration
类实际上只是一个伪包,用于将所有内容组合在一起。
英文:
Writing code that uses a class that may not exist on the classpath at runtime is not good idea. Writing the code so it doesn't cause NoClassDefFoundError
is troublesome.
The standard Spring Boot way can e.g. be seen in the source code of DataSourceConfiguration
.
In your case, you can do this:
abstract class XxxAutoConfiguration {
@Configuration
@ConditionalOnBean(AFactory.class)
@ConditionalOnMissingBean(Something.class)
@AutoConfigureOrder(1) // Try AFactory first
static class ASomething {
private AFactory aFactory;
@Autowired
void setaFactory(AFactory aFactory) {
this.aFactory = aFactory;
}
@Bean
Something something() {
return new Something(this.aFactory);
}
}
@Configuration
@ConditionalOnBean(BFactory.class)
@ConditionalOnMissingBean(Something.class)
@AutoConfigureOrder(2) // Try BFactory second
static class BSomething {
@Bean
Something something(BFactory bFactory) {
return new Something(bFactory);
}
}
}
As you can see, you can do it using @Autowired
or using a parameter, either way should work.
In case both AFactory
and BFactory
are present on the classpath, you can e.g. use @AutoConfigureOrder
to specify which one wins, as shown here. There are other @ConditionalXxx
annotations for more complex ways.
The XxxAutoConfiguration
class is really just a pseudo-package for keeping it all together.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论