如何让用户决定在 Spring 中将哪个实现用于接口?



我正在开发一个SDK,它将用于创建用于批处理的其他应用程序。有一个核心 a-api模块,它包含接口客户端

public interface Client {
void send();

}

core-a-impl,它包含客户端接口的几个实现 -HttpClientTcpClient
此外,还有一个核心模块core-b-impl,它使用客户端接口的特定实例。

public class SendingTasklet implements Tasklet {
@Autowired
private Client client
public void process() {
client.send();
} 

}
应该创建什么实例(HttpClientSftpClient)应该由用户决定,用户使用 SDK 创建应用程序。他还需要有能力为客户端创建自己的实现,并在SendingTasklet中使用它。来自核心依赖项的用户只能看到来自 -api模块的接口。对于依赖注入,我使用的是 Spring。特定模块的所有 bean 都是在每个模块中单独创建的。用户创建的 Bean 是在用户的配置类中创建的

@Configuration
public class UsersApplicationConf {
@Bean
public Client client {
return new UsersClient();
} 

}

问题是,在不公开用户应用程序的-impl模块详细信息的情况下,他应该能够决定可以从核心提供的实现中使用哪些客户端实现,或者他应该能够传递自己的一个。

第一个想法是在注入 SendingTasklet 时使用限定符,但是您需要为 SendingTasklet 中的每个实现创建一个单独的实例变量,这不是很好,因为如果客户端接口有更多的实现,它也需要更改SendingTasklet还有一个问题是,用户应该以某种方式决定使用仍然存在的实现。

我所做的,我为客户的应用程序公开了核心。因此,在他的配置中,他可以决定为客户端接口创建哪个实例。

@Configuration
public class UsersApplicationConf {
@Bean
public Client client {
return new HttpClient();
} 

}

但这也不是很聪明,我在想还有其他方法可以解决这个问题吗?

您可以使用此处提到的策略或工厂模式,但就我个人而言,我会使用 JSR 330,您可以在此处找到一个示例,下面是 spring 示例的代码块:

package spring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static spring.Spring.Platform;
@Configuration
@ComponentScan
public class Spring {
public static void main(String[] args) {
new AnnotationConfigApplicationContext(Spring.class);
}
@Autowired
@Platform(Platform.OperatingSystems.ANDROID)
private MarketPlace android;
@Autowired
@Platform(Platform.OperatingSystems.IOS)
private MarketPlace ios;
@PostConstruct
public void qualifyTheTweets() {
System.out.println("ios:" + this.ios);
System.out.println("android:" + this.android);
}
// the type has to be public!
@Target({ElementType.FIELD,
ElementType.METHOD,
ElementType.TYPE,
ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public static @interface Platform {
OperatingSystems value();
public static enum OperatingSystems {
IOS,
ANDROID
}
}
}
interface MarketPlace {
}
@Component
@Platform(Platform.OperatingSystems.IOS)
class AppleMarketPlace implements MarketPlace {
@Override
public String toString() {
return "apple";
}
}
@Component
@Platform(Platform.OperatingSystems.ANDROID)
class GoogleMarketPlace implements MarketPlace {
@Override
public String toString() {
return "android";
}
}

编辑:我没有测试代码,但我使用了javax.inject.Qualifier 使用 CDI 如果此代码不起作用,请告诉我我将使用 正确的组合和导入

最新更新