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

时间:2017-03-22 05:04:46

标签: java spring

我正在开发一个SDK,它将用于为批处理创建其他应用程序。有 core-a-api 模块,它保存接口 Client

public interface Client {
    void send();

}

core-a-impl ,它包含客户端接口的几个实现 - HttpClient TcpClient 。<登记/> 此外,还有一个核心模块 core-b-impl ,它使用 Client 接口的特定实例。

public class SendingTasklet implements Tasklet {
    @Autowired
    private Client client

    public void process() {
        client.send();
    } 

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

中创建的
@Configuration
public class UsersApplicationConf {

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

}

问题是,在某种程度上没有暴露用户应用程序的 -impl 模块细节,他应该能够决定从核心提供的实现中使用哪些客户端实现,或者他应该能够通过它自己的一个。

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

我做了什么,我为客户的应用程序公开了 core-a-impl 。因此,在他的配置中,他可以决定为 Client 接口创建的实例。

@Configuration
public class UsersApplicationConf {

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

}

但这也不是很聪明,而且我在想如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

您可以使用上面提到的策略或工厂模式here但我个人会使用JSR 330,您可以在代码块下面找到示例here,例如:

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如果此代码无法正常工作让我知道我会更新   正确的组合和进口

相关问题