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

Java 如何让用户决定在Spring中为接口使用哪个实现?,java,spring,Java,Spring,我正在开发一个SDK,它将用于创建用于批处理的其他应用程序。有一个core-a-api模块,用于保存客户端接口 公共接口客户端{ 无效发送; } 以及core-a-impl,它为客户端接口(HttpClient和TcpClient)提供了两个实现。 另外,还有一个核心模块core-b-impl,它使用客户机接口的特定实例。 } 应该创建哪个实例HttpClient或SftpClient应由使用SDK创建应用程序的用户决定。他还需要能够为客户端创建自己的实现,并在SendingTasklet中使

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

公共接口客户端{ 无效发送; }

以及core-a-impl,它为客户端接口(HttpClient和TcpClient)提供了两个实现。 另外,还有一个核心模块core-b-impl,它使用客户机接口的特定实例。

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

@配置 公共类UsersApplicationConf{ @豆子 公共客户端{ 返回新用户客户端; } }

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

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

我所做的是,为客户机的应用程序公开了core-a-impl。所以在他的配置中,他可以决定为客户机接口创建哪个实例

@配置 公共类UsersApplicationConf{ @豆子 公共客户端{ 返回新的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如果此代码不起作用,请告诉我我将使用更新 正确组合和导入


我认为,您可以实现一个条件自动连接bean。
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";
    }
}