模块化常见的闭合原理与反射

时间:2018-04-06 19:01:02

标签: java maven java-8

拥有这个maven项目结构

root pom
     ---> ModuleCore/pom.xml
     ---> ModuleA/pom.xml
     ---> ModuleB/pom.xml
     ---> ModuleC/pom.xml
     ---> ModuleD/pom.xml

模块A, B, C and D与模块Core有依赖关系,并且说ModuleAModuleB有依赖关系,ModuleB有依赖关系与ModuleC

通过这种依赖性分配,我们同意:

如果我修改

  ModuleCore

必须版本

  ModuleA/pom.xml
  ModuleB/pom.xml
  ModuleC/pom.xml
  ModuleD/pom.xml

如果我更新ModuleD,则无需更新版本。

如果我更新ModuleC

必须版本

  ModuleA/pom.xml
  ModuleB/pom.xml

在整个解释之后,我想要实现的是,没有模块之间存在依赖关系,只有ModuleCore

我的第一个建议是创建接口作为模块间通信的契约,并将该契约放在moduleCore中,然后通过reflection调用classpath实现的实现接口和调用。但是我对反思看起来很不舒服,

有人可以给我一些建议如何在不将所有代码移入ModuleCore的情况下应用通用闭包原理并制作一个整体?

使用Reflection的第一种方法的代码示例。

@Test
void dependencyWithModuleA() {
    Reflections reflections = new Reflections("com.modularization.ccp");
    Optional<Optional<?>> any = reflections.getSubTypesOf(MainA.class)
            .stream()
            .map(clazz -> {
                try {
                    MainA mainA = clazz.newInstance();
                    return Optional.of(mainA.main());
                } catch (InstantiationException | IllegalAccessException e) {
                    e.printStackTrace();
                }
                return Optional.empty();
            }).findAny();
    if (any.isPresent() && any.get().isPresent()) {
        System.out.println(any.get().get());
    }

}

重要的是要澄清它将在服务启动时完成的反射调用,以及实例引用它将使用Singleton模式进行保存,以避免性能问题。

请对所有关于这种方法的批评非常欢迎。

问候。

1 个答案:

答案 0 :(得分:1)

从问题的标签看,这个问题似乎仅限于Java 8.使用这个假设...

查看JDK中内置的ServiceLoader类。您可以在每个MainA个jar中声明META-INF/package.MainA文件中ModuleA-D的实现。然后找到这些实现:

ServiceLoader.load(MainA.class).iterator()

使用Java 9,事情会有所改变。现在JDK9模块可以直接声明它的服务,但它们仍然可以通过ServiceLoader发现,所以这种方法也有一定程度的未来验证。

显然,JDK之外还有更多解决方案,例如Spring有自动装配,或者ApplicationContext.getBeansOfType(Class),Java EE有javax.enterprise.inject.Instance,还有OSGi等......