MiraiForum

    • 注册
    • 登录
    • 搜索
    • 热门
    • 最新
    • 未解决
    • 标签
    • 群组
    • 友情链接
    1. 主页
    2. Karlatemp
    3. 帖子
    • 资料
    • 关注 0
    • 粉丝 13
    • 主题 16
    • 帖子 389
    • 最佳 50
    • 有争议的 1
    • 群组 3

    Karlatemp 发布的帖子

    • RE: 无内鬼,来点沙雕创意。

      全自动叫姐姐机

      发布在 开发交流
      Karlatemp
      Karlatemp
    • RE: 百度bike--极其简陋的百科插件

      虽然但是,为啥是自行车

      发布在 插件发布
      Karlatemp
      Karlatemp
    • RE: 今天你写代码了吗?

      下次一定写

      发布在 摸鱼区
      Karlatemp
      Karlatemp
    • RE: 插件已经在plugins里删掉了,启动怎么显示报错啊

      你需要在mcl的配置里一并删除

      发布在 使用交流
      Karlatemp
      Karlatemp
    • RE: 使用MiraiAndroid出现问题弹窗

      别开等待调试器

      发布在 BUG反馈
      Karlatemp
      Karlatemp
    • RE: LuckPerms - Mirai - 高级权限服务插件

      @cabbcat 我的设计中是能通过这种命令来基于 g** 的,但我并没有进行详细测试,如果有问题的话请发个issue,有时间我会去检查修复的

      发布在 插件发布
      Karlatemp
      Karlatemp
    • RE: 今天你写代码了吗?

      没有哦~~

      发布在 摸鱼区
      Karlatemp
      Karlatemp
    • RE: 如何在载入插件之前加载第三方依赖

      config.json直接写依赖,mcl会尝试去从 mirai-repo 获取版本信息,然而你的库在 mirai-repo 不存在,目前可用方法是直接把你的依赖直接扔进 plugins, 更好的依赖解决模式目前还未完成,见 https://github.com/mamoe/mirai/pull/1842

      Karlatemp created this issue in mamoe/mirai

      closed Redesign console plugin loading system #1842

      发布在 开发交流
      Karlatemp
      Karlatemp
    • RE: 加载Gradle变更时出错

      根据 Temp/sync.studio.tooling7.gradle, 此为 IDEA 内部问题, 请前往 JetBrains YouTrack 请求帮助

      发布在 开发交流
      Karlatemp
      Karlatemp
    • RE: GitHub源无法正常使用

      https://raw.githubusercontent.com/project-mirai/mirai-repo-mirror/master/

      发布在 使用交流
      Karlatemp
      Karlatemp
    • RE: [求助] Mirai-Console 插件打包依赖问题

      更换 kt 版本

      plugins {
          kotlin("jvm") version "1.5.30"
          kotlin("plugin.serialization") version "1.5.30"
      }
      
      发布在 开发交流
      Karlatemp
      Karlatemp
    • RE: LuckPerms - Mirai - 高级权限服务插件

      @yan-forever 您确认 LuckPerms 已经加载了吗, 执行 /status 看看

      发布在 插件发布
      Karlatemp
      Karlatemp
    • Java 动态模块系统 | Java dynamic module system

      前言

      在使用高版本的时候, 总会不可避免的接触到模块系统, 比如反射操作 java.base 已经十分困难. 既然 JDK 内部可以享受到模块的保护, 那么我们自己的代码是否也可以享受到模块系统的保护呢

      当然可以,而且也不是非常麻烦。

      使用模块,你将面对以下问题

      • 得到反射保护, 外部代码将不能通过反射强行修改/调用私有成员
      • 更严格的访问控制, 不能直接访问非 required 的模块
      • 失去 --add-opens=....=ALL-UNNAMED 的归属判断
      • 需要专门的 ClassLoader / 需要自行实现 ClassLoader

      使用模块的适用情况

      • 需要编写严格的附属(插件)系统
      • 需要保护自身代码/保护自身内存空间
      • 觉得弄着好玩

      定义一个模块

      注: 此处的定义指的是, 通过运行时代码在运行时定义一个模块.
      而不是大多数资料说的直接写一个 module-info.java

      要定义一个模块, 首先需要一个模块的描述符文件 (ModuleDescriptor), 可以从以编码文件读取 (ModuleDescriptor.read(InputStream) <- module-info.class), 也可以在运行时动态生成一个(ModuleDescriptor.newModule("name_of_module").build())

      jvm 通过包来区分模块, 而一个模块的全部包都需要提前指定, jvm 才会为这些包分配到一个模块内

      var moduleDescriptor = ModuleDescriptor.newModule("my.custom_module")
          .packages(Set.of("io.github.karlatemp.jmse.main"))
          .exports("io.github.karlatemp.jmse.main")
          .build();
      

      这里我们已经拥有了一个模块的描述符, 现在我们还需要一个模块描述的引用, 以及一个模块查找器以让 jvm 可以找到我们的模块

      var myModuleReference = new ModuleReference(
          moduleDescriptor, null
      ) {
          @Override public ModuleReader open() throws IOException {
              throw new UnsupportedOperationException();
          }
      }
      var myModuleFinder = new ModuleFinder() {
          @Override
          public Optional<ModuleReference> find(String name) {
              if (name.equals(moduleDescriptor.name())) {
                  return Optional.of(myModuleReference);
              }
              return Optional.empty();
          }
      
          @Override
          public Set<ModuleReference> findAll() {
              return Set.of(myModuleReference);
           }
      };
      

      最后,定义一个模块

      var bootLayer = ModuleLayer.boot();
      var myConfiguration = bootLayer.configuration().resolve(
          myModuleFinder, ModuleFinder.of(), Set.of(moduleDescriptor.name())
      );
      var classLoader = ClassLoader.getSystemClassLoader();
      var controller = ModuleLayer.defineModules(
          myConfiguration, List.of(bootLayer), $ -> classLoader
      );
      
      Class.forName("io.github.karlatemp.jmse.main.ModuleMain", false, classLoader)
          .getMethod("launch")
          .invoke(null);
      

      ServiceLoader / Class.forName(Module, String)

      还记得 需要专门的 ClassLoader / 需要自行实现 ClassLoader 吗, 虽然在上文已经成功定义了一个模块,但是只要使用 ServiceLoader / Class.forName(Module, String), 那么将无法找到对应的类, 因为一般的 ClassLoader 并没有专门处理动态加载的模块

      Analyze

      通过进行调用分析, 最终可以发现以上两个东西最终都进入到了下面的方法

      public class ClassLoader {
          final Class<?> loadClass(Module module, String name) {
              synchronized (getClassLoadingLock(name)) {
                  // First, check if the class has already been loaded
                  Class<?> c = findLoadedClass(name);
                  if (c == null) {
                      c = findClass(module.getName(), name);
                  }
                  if (c != null && c.getModule() == module) {
                      return c;
                  } else {
                      return null;
                  }
              }
          }
          protected Class<?> findClass(String moduleName, String name) {
              if (moduleName == null) {
                  try {
                      return findClass(name);
                  } catch (ClassNotFoundException ignore) { }
              }
              return null;
          }
      }
      

      不难发现, 由于默认没有处理模块, 导致指定搜索模块的时候将搜索不到动态定义的模块

      而 jdk.internal.loader.ClassLoader$AppClassLoader 并没有处理通过 ModuleLayer.defineModule 定义的模块, 于是也不能直接将模块定义到系统类加载器

      自行实现类加载器

      自行实现类加载器十分简单,只需要

      public class MyCustomClassLoader extends URLClassLoader {
          String moduleName;
      
          @Override
          protected Class<?> findClass(String moduleName, String name) {
              // System.out.println("Find class: " + moduleName + "/" + name);
              if (this.moduleName.equals(moduleName)) {
                  try {
                      return findClass(name);
                  } catch (ClassNotFoundException ignored) {
                  }
              }
              return super.findClass(moduleName, name);
          }
      }
      

      使用 JDK 内置的类加载器

      只需要实现 ModuleReference.open(): ModuleReader, 然后使用

      var controller = ModuleLayer.defineModulesWithOneLoader(
              myConfiguration,
              List.of(bootLayer),
              ClassLoader.getSystemClassLoader().getParent()
      );
      var classLoader = controller.layer().findLoader(moduleDescriptor.name());
      

      即可使用 JDK 内置的内加载器


      完整参考

      • java-module-system-explore
        • BootModuleByStandard.java
        • MyCustomClassLoader.java
      发布在 技术交流板块
      Karlatemp
      Karlatemp
    • RE: 使用java开发时JAutoSavePluginData不保存东西

      请问执行 /stop 后是否还有此问题,如果还有请前往仓库发issue

      发布在 开发交流
      Karlatemp
      Karlatemp
    • RE: 【每日沙雕图】沙雕小别墅

      IMG_20220105_124012_418.jpg

      发布在 摸鱼区
      Karlatemp
      Karlatemp
    • RE: 如何发送本地图片?

      use 2.9.1

      发布在 开发交流
      Karlatemp
      Karlatemp
    • RE: 如何发送本地图片?

      您的版本号?

      发布在 开发交流
      Karlatemp
      Karlatemp
    • RE: mirai2.9.0版本,私聊发送语音无法播放

      您的非加密语音指的啥

      发布在 BUG反馈
      Karlatemp
      Karlatemp
    • RE: 最近mirai的图片发送不出去了

      the version of mirai?

      发布在 BUG反馈
      Karlatemp
      Karlatemp
    • RE: -----

      您在说什么?

      发布在 BUG反馈
      Karlatemp
      Karlatemp
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 19
    • 20
    • 5 / 20