SharedSecrets机制是如何工作的?

2023-11-29

jdk.internal.misc.SharedSecrets自我描述为:

“共享秘密”的存储库,这是一种机制 调用另一个包中的实现私有方法而不需要 使用反射。包私有类实现了一个公共类 接口并提供调用包私有方法的能力 在该包内;实现该接口的对象是 通过访问受到限制的第三个包提供。 该框架避免了使用反射的主要缺点 为此,即失去编译时检查。

有人可以提供一个示例来演示这一机制如何使一个包中的类能够访问不同包中的包私有方法吗?


Quoting 安德鲁·约翰·休斯:

当浏览 OpenJDK 的 VM 项目时,我注意到他们对此有一个相当有趣的解决方案。这被封装在 sun.misc.SharedSecrets 中。此类提供对许多公共接口实例的访问,例如 sun.misc.JavaLangAccess。实际的实现作为适当包中的内部类提供,例如java.lang,它可以访问其中的私有和包私有变量和方法。

假设您的 API 类分散在多个包中。您希望他们能够访问彼此的内部结构,而不会将其暴露给最终用户。你做什么工作?

选项 1:不使用 Java 模块

  1. 创建一个将从公共 Javadoc 中省略的“内部”包(例如com.example.internal)
  2. 在内部包中声明一个或多个接口,引用您尝试访问的私有功能。
  3. 声明一个公共类(例如共享秘密)在内部包中保存这些接口的实现。
  4. 在 API 类中使用静态初始化器来获取/设置这些接口的实现共享秘密.
  5. 现在,API 类可以通过受信任的中介来访问彼此的内部结构(共享秘密).

选项 2:使用 Java 模块

  1. 假设您有两个模块:main and test,而你想要test访问内部的私有或包私有方法和字段main.
  2. 声明一个公共类共享秘密在主模块内部,在非导出的包中。例如:main.internal.SharedSecrets.
  3. In main's 模块信息.java, add exports main.internal to test.
  4. 意思是,包主.内部仅可由模块访问test.
  5. Because 共享秘密是公开的,任何人main(甚至来自不同的包)可以将桥接功能或字段推入其中。实际上它也可以以另一种方式工作(test可以将桥接功能推入main)但迄今为止我从未需要这样做。
  6. 现在,任何时候test希望访问内部结构main,它只是通过调用共享秘密.

这个解决方案特别好,因为生成的 Javadoc 和 IDE 自动完成功能看起来会干净很多。

具体例子

External Users
├── external
│   └── EndUser.java
└── module-info.java

Library
├── library
│   ├── character
│   │   └── Character.java
│   ├── story
│   │   └── Story.java
│   └── internal
│       ├── SharedSecrets.java
│       └── SecretCharacter.java
└── module-info.java
  • 我们想要曝光Character的内部结构为Story没有EndUser获得访问权限。

最终用户代码


外部/EndUser.java:

package external;

import library.character.Character;
import library.story.Story;

public class EndUser
{
    public static void main(String[] args)
    {
        Story story = new Story();
        story.introduce(Character.HARRY_POTTER);
        story.introduce(Character.RON_WEASLEY);
        story.introduce(Character.HERMIONE_GRANGER);
    }
}

模块信息.java:

module external
{
    requires library;
}

库代码


库/故事/Story.java

package library.story;

import library.character.Character;
import library.internal.SecretCharacter;
import library.internal.SharedSecrets;

public final class Story
{
    private static final SharedSecrets sharedSecrets =
      SharedSecrets.INSTANCE;

    public void introduce(Character character)
    {
        System.out.println(character.name() + " enters the room and says: " + 
          sharedSecrets.secretCharacter.getPhrase(character));
    }
}

库/字符/Character.java:

package library.character;

import library.internal.SecretCharacter;
import library.internal.SharedSecrets;

public enum Character
{
    HARRY_POTTER
    {
        @Override
        String getPhrase()
        {
            return "Your bird, there was nothing I could do. He just caught fire.";
        }
    },
    RON_WEASLEY
    {
        @Override
        String getPhrase()
        {
            return "Who are you and what have you done with Hermione Granger?";
        }
    },
    HERMIONE_GRANGER
    {
        @Override
        String getPhrase()
        {
            return "I'm not an owl!";
        }
    };

    static
    {
        SharedSecrets.INSTANCE.secretCharacter = new SecretCharacter()
        {
            @Override
            public String getPhrase(Character character)
            {
                return character.getPhrase();
            }
        };
    }

    abstract String getPhrase();
}

库/内部/SharedSecrets.java:

package library.internal;

public enum SharedSecrets
{
    INSTANCE;
    public SecretCharacter secretCharacter;
}

库/内部/SecretCharacter.java:

package library.internal;

import library.character.Character;

public interface SecretCharacter
{
    String getPhrase(Character character);
}

模块信息.java:

module library
{
    exports library.character;
    exports library.story;
}

Output

哈利波特走进房间说:你的鸟儿,我无能为力。他刚刚着火了。

罗恩·韦斯利走进房间并说道:你是谁?你对赫敏·格兰杰做了什么?

HERMIONE_GRANGER 走进房间并说道: 我不是猫头鹰!

Notice

  • Character.getPhrase()受包保护。
  • Story位于不同的包中。
  • 通常情况下Story将无法调用Character.getPhrase();然而,SharedSecrets allows Character与其信任的类共享访问权限。
  • Story调用SharedSecrets.INSTANCE.secretCharacter它使用匿名嵌套类来访问Character的内部结构。
  • Story可以访问SharedSecrets因为两者位于同一个模块中,但是外部用户无法访问它,因为module-info.java不导出该包。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SharedSecrets机制是如何工作的? 的相关文章

随机推荐

  • 测试套件、测试用例和测试类别之间的区别

    测试套件 测试用例和测试类别之间有什么区别 我找到了部分答案here 但是类别呢 测试用例是为测试特定执行路径而开发的一组测试输入 执行条件和预期结果 通常情况下 案例是单一方法 测试套件是相关测试用例的列表 套件可能包含特定于所包含案例的
  • 如何使 gdb 前端在汇编源代码窗口中显示当前指令箭头?

    我正在 Linux Arch 64 上进行一些 x86 汇编程序编码 使用 nasm 进行汇编 使用 ld 进行链接 从而创建一个 32 位可执行文件 wordcount wordcount o ld o wordcount wordcou
  • C++ 中值类型的限制范围

    假设我有一个 LimitedValue 类 它保存一个值 并在 int 类型 min 和 max 上进行参数化 您可以将其用作保存只能在特定范围内的值的容器 你可以这样使用它 LimitedValue lt float 0 360 gt s
  • 如何使用java设置生成的pdf417条形码的宽度

    您好 我正在生成 pdf417 条形码 为此我遵循this link try String a Microsoft String b wkejew PDF417 barcode new PDF417 barcode setData a b
  • 如何限制 Bootstrap Datepicker 中的可选日期范围?

    我需要使用日期选择器 它为我提供了限制可选日期的选项 我们一直在使用 jQuery UI 它用于使用 minDate maxDate 选项来支持它 id date datepicker minDate 1 maxDate 1M 10D 最近
  • 使平滑的锚标记滚动与滚动捕捉兼容

    我在用 html scroll behavior smooth 实现平滑滚动到 html 锚标记 我还使用启用垂直滚动捕捉scroll snap type and scroll snap align在 css 中 如下面的代码所示 问题是我
  • Jena Sparql 和构造

    CONSTRUCT是 SPARQL 结果子句的替代SELECT 不是返回结果值表 CONSTRUCT返回 RDF 图 例如 在以下 Java 代码中运行此查询会生成HttpException 406 Unacceptable 但如果不是CO
  • 该应用程序不允许查询方案 XYZ://

    您可能认为这是一个重复的问题 但事实并非如此 我完全知道有关该问题的所有答案canOpenURL及其在 iOS 9 上的注意事项 但这是我的问题 我正在尝试检查我的设备上是否安装了特定的应用程序 均由我开发 我已宣布该计划AppA as
  • 在 Python 中下载文件

    import urllib2 sys if len sys argv 3 print Usage download py
  • 为 iOS 模拟器构建,但链接框架“****.framework”是为 iOS 构建的

    我无法再在模拟器上运行我的应用程序 网上建议我编辑我的project pbxproj 但这似乎不起作用 如何重新获得在模拟器上运行项目的能力 并仍然能够在设备上执行此操作 我正在开发另一个项目 该项目使用许多相同的框架 但它在模拟器上运行
  • 存档时链接器命令失败

    我想要archiveReact Native 项目用户使用最新的 Xcode 但总是失败 因为链接器命令失败 当我跑步时xcodebuild verbose Ld命令 那么错误是这样的 ld file not found build xxx
  • 合并时不会出现空格冲突

    我遇到了一个问题 其中一个大型提交更改了大约一千行代码 删除了行尾的空格并删除了制表符之前的空格 该项目还有大约 50 个拉取请求 当我的提交被合并时 所有这些请求都会发生冲突 有没有什么方法可以设置 git 以便在合并未来的提交时 它会忽
  • 带前导零的数字的反转

    我们如何反转 number 中带有前导零的数字 例如 如果输入是004 输出应该是 400 我写了下面的程序 但它仅在输入中没有前导零时才有效 int num cout lt lt Enter number lt
  • Karate API - Hello World 示例,但 POST (GraphQL) 创建/检索用户

    我的场景中有两个 graphQL 帖子 就像 Hello World 示例一样 我想创建一个用户 API createUser 然后检索该用户 API getUser 以运行断言 我不确定它是否是 graphQL Post 查询让我绊倒的
  • Swift:将符合 FloatingPoint 的值转换为 Double

    我正在编写浮点协议的扩展 我想以任何可能的方式将其转换为 Double extension FloatingPoint var toDouble Double return Double exactly self 0 compile err
  • 如何从媒体存储中删除单个文件?

    这段代码有效 getActivity getContentResolver delete MediaStore Audio Media EXTERNAL CONTEN T URI TITLE songdetails get index so
  • 将容器从 ACR 部署到 AKS

    我有一个容器 其中有一个非常简单的 Web 应用程序 已上传到 Azure 容器注册表 我创建了一个 AKS 集群 现在我想将容器部署到 AKS 中 我找到了许多关于此的教程 但它们似乎都引用了 YAML 文件 而这些文件的解释很少或根本没
  • java - 比较月份和年份的两个日期值

    我需要匹配两个日期 如果它们的月份 年份相同 我应该返回 true 否则返回 false 根据我的搜索 我找到了以下解决方案 还有其他更好的方法来进行这种比较吗 Calendar cal1 Calendar getInstance Cale
  • 如何使用带通配符的 AzureSearch

    我想搜索名称为 14009 00080300 的字段 并且希望仅搜索其中的一部分 例如 14009 000803 时获得命中 使用这段代码我没有得到任何点击 search 14009 000803 count true top 10 有没有
  • SharedSecrets机制是如何工作的?

    jdk internal misc SharedSecrets自我描述为 共享秘密 的存储库 这是一种机制 调用另一个包中的实现私有方法而不需要 使用反射 包私有类实现了一个公共类 接口并提供调用包私有方法的能力 在该包内 实现该接口的对象