Java 在内部使用共享类库,但不在发布的SDK中提供对它们的访问

Java 在内部使用共享类库,但不在发布的SDK中提供对它们的访问,java,android,sdk,Java,Android,Sdk,经过一些研究,我无法找到最好的方法。将有某些颜色类,我想在多个项目之间共享。我们叫其中一个EncryptedColor。由于它是跨多个项目使用的,我当然不希望它有多个副本。否则,我将需要确保在一个位置的更新将需要在任何地方更新。但是,我们向客户提供的一些已发布的SDK中需要这些类 我如何设计它,使我可以使用这些类,但不向它们提供它们不需要从SDK访问的类。我不希望无用的类变得可见,并淹没他们真正需要看到的较小的类子集 到目前为止,我已经想到了几种方法,但并不十分理想: 尝试使用doclet结构来

经过一些研究,我无法找到最好的方法。将有某些颜色类,我想在多个项目之间共享。我们叫其中一个EncryptedColor。由于它是跨多个项目使用的,我当然不希望它有多个副本。否则,我将需要确保在一个位置的更新将需要在任何地方更新。但是,我们向客户提供的一些已发布的SDK中需要这些类

我如何设计它,使我可以使用这些类,但不向它们提供它们不需要从SDK访问的类。我不希望无用的类变得可见,并淹没他们真正需要看到的较小的类子集

到目前为止,我已经想到了几种方法,但并不十分理想:

尝试使用doclet结构来隐藏javadoc中的调用,比如doclava。Javadoc还没有完全实现自己的隐藏机制。据我所知,这并不会使函数不可见,但有一点提到,使用调用时需要反射。我不明白javadoc是如何做到这一点的,所以我肯定错过了什么。 安卓自己设计了它,它似乎迫使源代码中包含的方法中的某些@hide属性进行反射。但从声音上看,系统隐藏了这些,然后在加载时使用不同的jar,使它们在启动时可见。这里可能没用。 如果我将共享类保留在相同的包名中,我可以访问默认和受保护的成员,但是……那么我将所有使用这些名称的类保留在相同的包名中。也不太理想,但如果我需要的话,可以用那种方式来做。可能会因大量共享资源而失控。
在这种情况下通常采取什么方法?到目前为止,我不喜欢我的发现和思考过程。

我的建议是 为颜色类创建接口,可以使用ServiceLoader类调用实现。然后,您只需将颜色类分为两个包——一个可以用SDK打包并分发的公共包,以及一个用于您希望成为内部类的私有包。只要jar文件位于项目的类路径中,ServiceLoader就会找到所有可用的颜色类

例如,如果您的颜色类作为示例具有如下公共接口:

public interface MyAppColor {
    public int getRed();

    public int getGreen();

    public int getBlue();

    public int getAlpha();

    public void setRed(int red);

    public void setGreen(int green);

    public void setBlue(int blue);

    public void setAlpha(int alpha);

    public boolean isValid();

    public void doSomething(Object arg); 
}
然后,您可以在jar文件中有一组实现类,jar中包含一个服务描述符文件,路径如下:

META-INF/services/com.my.app.MyAppColor
该文件的文本只是jar中实现接口的类的列表-每行一个:

com.my.app.MyPublicAppColor
com.my.app.MyEncryptedPublicAppColor
com.my.app.MyOtherPublicAppColor
等等。然后,您所要做的就是创建一个工厂来实例化正确的类型,它可以像下面这样简单:

public class MyAppColorFactory {
    private static ServiceLoader<MyAppColor> serviceLoader = ServiceLoader.load(MyAppColor.class, null);
    public static MyAppColor get(String className){
        if (className != null){
            for (MyAppColor c : serviceLoader){
                if (className.equals(c.getClass().getName())){
                    return c;
                }
            }
        }
        return null;
    }
}

我的建议是 为颜色类创建接口,可以使用ServiceLoader类调用实现。然后,您只需将颜色类分为两个包——一个可以用SDK打包并分发的公共包,以及一个用于您希望成为内部类的私有包。只要jar文件位于项目的类路径中,ServiceLoader就会找到所有可用的颜色类

例如,如果您的颜色类作为示例具有如下公共接口:

public interface MyAppColor {
    public int getRed();

    public int getGreen();

    public int getBlue();

    public int getAlpha();

    public void setRed(int red);

    public void setGreen(int green);

    public void setBlue(int blue);

    public void setAlpha(int alpha);

    public boolean isValid();

    public void doSomething(Object arg); 
}
然后,您可以在jar文件中有一组实现类,jar中包含一个服务描述符文件,路径如下:

META-INF/services/com.my.app.MyAppColor
该文件的文本只是jar中实现接口的类的列表-每行一个:

com.my.app.MyPublicAppColor
com.my.app.MyEncryptedPublicAppColor
com.my.app.MyOtherPublicAppColor
等等。然后,您所要做的就是创建一个工厂来实例化正确的类型,它可以像下面这样简单:

public class MyAppColorFactory {
    private static ServiceLoader<MyAppColor> serviceLoader = ServiceLoader.load(MyAppColor.class, null);
    public static MyAppColor get(String className){
        if (className != null){
            for (MyAppColor c : serviceLoader){
                if (className.equals(c.getClass().getName())){
                    return c;
                }
            }
        }
        return null;
    }
}

简短回答:您不能隐藏/删除这些类,因为您的应用程序在运行时需要它们

在我看来,你有3种选择:

将类访问更改为包专用。是的,这样做并不会使访问它们变得不可能,但是这些类不会被直接访问

删除类并创建API。你想隐藏逻辑?例如,删除它并通过RESTAPI提供它。这可能很困难,也可能不可能,具体取决于您的架构

使用Spring或使用Java的ServiceLoader以动态方式使用Class.forName创建这些类的所有实例,如@Steve K answer。因此,您将能够从主jar中删除这些类,并在某种程度上使它们更私有。同样,课程也会在这里,但不太容易访问


简短回答:您不能隐藏/删除这些类,因为您的应用程序在运行时需要它们

在我看来,你有3种选择:

将类访问更改为包privat E是的,这样做并不会使访问它们变得不可能,但是这些类不会被直接访问

删除类并创建API。你想隐藏逻辑?例如,删除它并通过RESTAPI提供它。这可能很困难,也可能不可能,具体取决于您的架构

使用Spring或使用Java的ServiceLoader以动态方式使用Class.forName创建这些类的所有实例,如@Steve K answer。因此,您将能够从主jar中删除这些类,并在某种程度上使它们更私有。同样,课程也会在这里,但不太容易访问

仅部署所需代码: -在开发中只使用所需的源 因为您有一个完整的库和许多部署,每个部署使用不同的组件,所以执行建议的最简单方法是只使用您需要的源;没有一个图书馆。您可以忽略未使用的源。这将只发送所需的代码

-创建图书馆 这将只允许访问库的公共组件,其他所有内容都不可调用。但是,它仍然会发送所有代码

-创建一个API作为 这将需要web访问,对于性能代码{any code really}来说并不理想。此方法不会提供任何sdk代码

- 使用正确的工具很容易。混淆会将生产代码中的类和方法名称更改为乱码。这将使该库基本上对除您之外的任何人都不可用。这将发送所有代码,但它将被混淆

- 您可以将java编译成机器代码,并将其用于生产或用作api。您还可以使用本机语言{不可取}创建api。

仅部署所需代码: -在开发中只使用所需的源 因为您有一个完整的库和许多部署,每个部署使用不同的组件,所以执行建议的最简单方法是只使用您需要的源;没有一个图书馆。您可以忽略未使用的源。这将只发送所需的代码

-创建图书馆 这将只允许访问库的公共组件,其他所有内容都不可调用。但是,它仍然会发送所有代码

-创建一个API作为 这将需要web访问,对于性能代码{any code really}来说并不理想。此方法不会提供任何sdk代码

- 使用正确的工具很容易。混淆会将生产代码中的类和方法名称更改为乱码。这将使该库基本上对除您之外的任何人都不可用。这将发送所有代码,但它将被混淆

-
您可以将java编译成机器代码,并将其用于生产或用作api。您还可以使用本机语言{不可取}创建api。

因此有些SDK需要这些类,但不是所有的?@ToYonos有内部使用的应用程序使用这些类,外部客户SDK和各种工具也使用它们。当然有很多课程,而不仅仅是一门。但为了简单起见,我只想关注其中一个。因为它在任何地方都被使用,所以我希望它存在于一个地方。我只是不想把这些类暴露给不需要它们的外部SDK。好的。但有一件事,您说过外部客户SDK[…]在不需要它们的地方使用它们和外部SDK。我是不是遗漏了什么?@ToYonos我会简化它。项目1、2、3使用颜色类。项目1是一个客户SDK。项目2和项目3并非如此。都使用颜色类。项目1不需要公开颜色类,也不应该公开。否则,它会在SDK的16个左右有用的类中塞满120个颜色类,这真的不应该困扰客户。因此,一些SDK需要这些类,但不是全部?@ToYonos有一些内部应用程序使用这些类,外部客户SDK和各种工具也使用它们。当然有很多课程,而不仅仅是一门。但为了简单起见,我只想关注其中一个。因为它在任何地方都被使用,所以我希望它存在于一个地方。我只是不想把这些类暴露给不需要它们的外部SDK。好的。但有一件事,您说过外部客户SDK[…]在不需要它们的地方使用它们和外部SDK。我是不是遗漏了什么?@ToYonos我会简化它。项目1、2、3使用颜色类。项目1是一个客户SDK。项目2和项目3并非如此。都使用颜色类。项目1不需要公开颜色类,也不应该公开。否则,它将向SDK的16个左右有用的类中注入120个颜色类,这真的不应该困扰客户。但所有颜色类的实现都将出现在SDK中,即使是在客户版中?为什么要向SDK中添加您不希望可用的类?您可以有两个不同的jar文件用于公共和私有文件,
根据op,即使是SDK也需要所有的颜色类,所以即使是私有包也需要。事实上,内部项目和sdk有相同的需求,但sdk必须对用户隐藏一些依赖项。这不是我从他的帖子中得到的。听起来SDK需要一个子集。但是,他可以用源代码将公共类打包到jar中,而不使用源代码将私有类打包,或者类似的东西。Android工程师之一:ServiceLoader是来自Java语言的东西,在Android上并不真正相关。我建议不要使用它。但是所有的颜色类实现都会出现在SDK中,即使是在customer one中也会出现。为什么要向SDK中添加您不想使用的类?你可以有两个不同的jar文件,一个是公共的,另一个是私有的,你的SDK中不包含私有的jar。根据op,即使是SDK也需要所有的颜色类,所以即使是私有的包也需要。事实上,内部项目和sdk有相同的需求,但sdk必须对用户隐藏一些依赖项。这不是我从他的帖子中得到的。听起来SDK需要一个子集。但是,他可以用源代码将公共类打包到jar中,而不使用源代码将私有类打包,或者类似的东西。Android工程师之一:ServiceLoader是来自Java语言的东西,在Android上并不真正相关。我建议不要使用它。