java - Spring注入(inject)不同的服务实现

标签 java design-patterns

这就是我们目前所拥有的:

interface ReportService {

    Report generate();
  }

以及接口(interface)实现:

@Service
public class ReportService_1Impl implements ReportService {

    public Report generate() {

        System.out.println("Report Service 1: generate Report.");
        return new Report();
    }
}

这段代码新的业务需求是什么:

  • 实现新的 ReportService_2将与新的报告引擎通信,但新服务仍然具有相同的 generate()具有相同签名的方法;
  • 基于某些预定义的配置,实现在运行时在这些服务之间切换的可能性;
  • 作为一种选择:考虑引入新产品的能力 ReportServices在最近的特征中。

好的,让我们开始实现上面提到的所有步骤:

第 1 步:

ReportService_2 :

@Service
@Qualifier("ReportService_2")
public class ReportService_2Impl implements ReportService {
    public Report generate() {

        System.out.println("Report Service 2: generate Report.");
        return new Report();
    }
}

添加@Qualifier("ReportService_1")对于 ReportService_1Impl

@Service
@Qualifier("ReportService_1")
public class ReportService_1Impl implements ReportService {

    public Report generate() {

        System.out.println("Report Service 1: generate Report.");
        return new Report();
    }
}

第 2 步:

如何根据配置在运行时在2个服务之间切换?

坦白说,我不知道如何正确执行这个任务,我刚刚引入了新的 ReportService扮演ReportService_1Impl的容器或包装器的角色和ReportService2_Impl并确定需要使用哪些实现:

@Service
public class ReportServiceImpl implements ReportService {

    @Autowired
    @Qualifier("ReportService_1")
    private ReportService reportService_1;
    @Autowired
    @Qualifier("ReportService_2")
    private ReportService reportService_2;

    private ReportService getActiveReportService() {

        return true ? reportService_1 : reportService_2;
    }

    public Report generate() {

        return getActiveReportService().generate();
    }
}

看起来很丑,但我相信我们可以忍受。

最后一步,我需要实现以下要求:

考虑引入新产品的能力ReportService's在最近的特征中。

我不知道如何正确实现这一点,因为在当前的实现中,每次我都会添加新的 ReportService_N我需要记住,我肯定需要注入(inject)新创建的 ReportService_NReportServiceImpl它看起来像:

@Service
public class ReportServiceImpl implements ReportService {

    @Autowired
    @Qualifier("ReportService_1")
    private ReportService reportService_1;
    @Autowired
    @Qualifier("ReportService_2")
    private ReportService reportService_2;
    @Autowired
    @Qualifier("ReportService_3")
    private ReportService reportService_3;
    @Autowired
    @Qualifier("ReportService_4")
    private ReportService reportService_4;
    @Autowired
    @Qualifier("ReportService_N")
    private ReportService reportService_N;

相信,此类问题过去已经解决过多次,并且已经定义了我需要使用的一些模式。

有人可以给我建议或模式名称来帮助我解决最后一个场景的问题吗?

最佳答案

您使事情变得更加复杂,相反,您可以使用 @Resource(name="${reportService}") 轻松动态分配 bean,如下所示,即,您实际上可以将 bean 外部化名称(无论您想在运行时注入(inject)哪个)到 application.properties

我已经使用Controllerautowire您的ReportService,但同样可以在您喜欢的任何 Spring 组件中完成。

@Controller
public class YourContrller {

    @Autowired
    @Resource(name="${reportService}")
    private ReportService reportService;

    public Report generate() {

        return reportService.generate();
    }
}

@Service("ReportService_1")//name this service as ReportService_1
public class ReportService_1Impl implements ReportService {
  //actual code
}

@Service("ReportService_2")//name this service as ReportService_2
public class ReportService_2Impl implements ReportService {
  //actual code
}

您需要在 application.properties 中配置诸如 reportService=ReportService_1 bean name 之类的属性

What about the scenario, when configuration stored in DB? or case, when we need to make a decision which service to use based on some incoming parameters?

如果您希望从数据库配置属性,那么您需要创建一个新的@PropertySource并告诉spring您使用它,这是一个创建数据库propertysource的简单示例here .

下一种情况是,如果您想使用某些变量根据某些 if -else 条件动态传递对象,那么您需要传递 ReportService 动态对象(使用多态性),正如很好地解释的 here

关于java - Spring注入(inject)不同的服务实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43031817/

相关文章:

java - 在JAVA中读取格式为PKCS1的RSA私钥

java - 参数类就像类一样

java - 单链表最大键搜索

c++ - 等待条件的非线程替代方法。 (编辑 : Proactor pattern with boost. asio?)

Javascript 揭示模块模式、公共(public)属性

java - 是否可以预览 Java 编译器将生成哪些类文件?

java - 创建一个抑制 CustomTooltip 的自定义 JButton

c# - ASP.NET MVC 项目层

c# - 使用部分类是一种好的做法/设计吗?

c++ - 创建对象而不是构造函数的静态方法