MiraiForum

    • 注册
    • 登录
    • 搜索
    • 热门
    • 最新
    • 未解决
    • 标签
    • 群组
    • 友情链接

    插件里Spring的AnnotationConfigApplicationContext扫描不到bean

    开发交流
    4
    13
    785
    正在加载更多帖子
    • 从旧到新
    • 从新到旧
    • 最多赞同
    回复
    • 在新帖中回复
    登录后回复
    此主题已被删除。只有拥有主题管理权限的用户可以查看。
    • H
      hundun000 ⭐2021⭐ 最后由 hundun000 编辑

      mirai 2.6.7。
      (一个位于com.hundun.mirai.bot.core包的类)使用以下代码创建ApplicationContext并扫描com.hundun.mirai.bot包,打印beans的名字。

          AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
      
          context.scan("com.hundun.mirai.bot");
      
          context.refresh();
      
          console.getLogger().info("ApplicationContext created, has beans = " + Arrays.toString(context.getBeanDefinitionNames()));
      

      IDE单元测试里加载插件,可以扫到com.hundun.mirai.bot里的beans:
      3ca90bde-9388-4e20-bb82-6f4fb108fe47-image.png

      buildPlugin以后放入mcl,启动后扫不到com.hundun.mirai.bot里的beans:
      47015b15-d522-4661-856d-b32ddc7b5d64-image.png

      确认插件jar里com.hundun.mirai.bot包内容正常:
      287f18cd-f9a1-430e-a9c2-cb80a9a3d986-image.png

      1 条回复 最后回复 回复 引用 0
      • cssxsh
        cssxsh 最后由 编辑

        具体是想实现什么啊,使用mybaits? 还是 构建 http api ?, spring 框架不建议在插件里使用

        1 条回复 最后回复 回复 引用 0
        • ryoii
          ryoii 梦中的鸡翅 最后由 编辑

          Spring 默认使用 DefaultResourceLoader 加载类,DefaultResourceLoader 会设置为当前线程的默认类加载器,大概率就是 AppClassLoader

          因此,Spring 的 DefaultResourceLoader 只能加载 classpath 下的类

          Mirai Console 对每一个插件使用了单独的 URLClassLoader 加载 Jar 包,插件中的类是不在 classpath 下的

          1 条回复 最后回复 回复 引用 0
          • ryoii
            ryoii 梦中的鸡翅 最后由 编辑

            外部加载 Jar 包是插件系统常用的做法,所以和 Srping 默认从 classpath 下读取 bean 是冲突的,所以我一直不推荐使用 spring 容器开发各种插件。

            虽然我没有做过,但是可以提供一个大概率可行的思路。

            • 额外开启 一个线程用于用于初始化 SpringContext
            • 将这个线程的 TCCL (Thread Context Class Loader) 设置为插件主体(JvmPlugin) 的类加载器

            这样 SpringContext 在初始化的时候应该就会取到插件的类加载器。注意,这个 SpringContext 是否能扫描到插件之外的 Bean 取决与 Mirai Console 的实现

            cssxsh H 2 条回复 最后回复 回复 引用 0
            • cssxsh
              cssxsh @ryoii 最后由 编辑

              @ryoii

                  val thread = Thread.currentThread()
                  val oc = thread.contextClassLoader
                  try {
                      thread.contextClassLoader = XXXPlugin::class.java.classLoader
                      AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
                      context.scan("com.hundun.mirai.bot");
                      context.refresh();
                      console.getLogger().info("ApplicationContext created, has beans = " + Arrays.toString(context.getBeanDefinitionNames()));
                      
                  finally {
                      thread.contextClassLoader = oc
                  }
              

              大概这样呗

              1 条回复 最后回复 回复 引用 0
              • H
                hundun000 ⭐2021⭐ 最后由 编辑

                @cssxsh 目前想要Ioc容器实现、MongoDB数据访问实现,openfeign实现。

                我是在考虑和尝试,使用spring,(1)花费一定的前期工作量在 @ryoii 所说的替换Spring的一些默认实现以适配mirai插件。(2)后期可以获得上述3类Spring的便利。

                如果实际情况是(1)带来的工作量/不稳定性,超过了(2)的好处,那我就不用spring了。目的是插件内省事,不打算取插件以外的bean。

                1 条回复 最后回复 回复 引用 0
                • H
                  hundun000 ⭐2021⭐ @ryoii 最后由 编辑

                  @ryoii 在 插件里Spring的AnnotationConfigApplicationContext扫描不到bean 中说:

                  外部加载 Jar 包是插件系统常用的做法,所以和 Srping 默认从 classpath 下读取 bean 是冲突的,所以我一直不推荐使用 spring 容器开发各种插件。

                  虽然我没有做过,但是可以提供一个大概率可行的思路。

                  • 额外开启 一个线程用于用于初始化 SpringContext
                  • 将这个线程的 TCCL (Thread Context Class Loader) 设置为插件主体(JvmPlugin) 的类加载器

                  这样 SpringContext 在初始化的时候应该就会取到插件的类加载器。注意,这个 SpringContext 是否能扫描到插件之外的 Bean 取决与 Mirai Console 的实现

                  试了,可行

                  lc6a 1 条回复 最后回复 回复 引用 0
                  • lc6a
                    lc6a @hundun000 最后由 编辑

                    @hundun000 你好,我也是使用Spring框架做机器人项目,我比较好奇你打包的jar包具体内容。能否发一份你打包的使用Spring的插件jar包?如果你当前项目不方便公布的话,能否用spring写个hello world的插件,然后打包发我一份?如果论坛不方便发送的话,我QQ1952511149。非常感谢!

                    lc6a H 2 条回复 最后回复 回复 引用 0
                    • lc6a
                      lc6a @lc6a 最后由 编辑

                      @lc6a 在 插件里Spring的AnnotationConfigApplicationContext扫描不到bean 中说:

                      @hundun000 你好,我也是使用Spring框架做机器人项目,我比较好奇你打包的jar包具体内容。能否发一份你打包的使用Spring的插件jar包?如果你当前项目不方便公布的话,能否用spring写个hello world的插件,然后打包发我一份?如果论坛不方便发送的话,我QQ1952511149。非常感谢!

                      我之前打算解决这个问题的,被一些事情耽搁了。你如果能顺便提供源码就更好了,我可能会尝试解决此问题。如果我解决了,我可以跟你分享分享。

                      1 条回复 最后回复 回复 引用 0
                      • H
                        hundun000 ⭐2021⭐ @lc6a 最后由 编辑

                        @lc6a 主项目在转spring的重构中,太乱了。写成了demo项目

                        1 条回复 最后回复 回复 引用 0
                        • H
                          hundun000 ⭐2021⭐ 最后由 hundun000 编辑

                          继续实验了下,有如下发现:

                          1. 与其新建线程然后让Spring默认使用当前线程的默认类加载器,其实可以直接context.setClassLoader。
                          2. 不一定要插件主体(JvmPlugin) 的类加载器,似乎任意一个插件jar里的类都行,所以这里直接用this.getClass().getClassLoader()。
                              context = new AnnotationConfigApplicationContext();
                          
                              context.setClassLoader(this.getClass().getClassLoader());
                          
                              context.scan("com.hundun.mirai.bot");
                          
                              context.refresh();
                          

                          不过上述操作只能让Ioc容器生效。距离我的需求的后两项,试了下,不止@EnableMongoRepositories,@EnableFeignClients这么简单,还需替换其他的Spring默认值,目前还在研究。

                          cssxsh H 2 条回复 最后回复 回复 引用 0
                          • cssxsh
                            cssxsh @hundun000 最后由 编辑

                            @hundun000
                            检索一遍spring 里 classloader的调用呗

                            1 条回复 最后回复 回复 引用 0
                            • H
                              hundun000 ⭐2021⭐ @hundun000 最后由 编辑

                              @hundun000 在 [插件里Spring的AnnotationConfigApplicationContext扫描不到bean]

                              距离我的需求的后两项,试了下,不止@EnableMongoRepositories,@EnableFeignClients这么简单,还需替换其他的Spring默认值,目前还在研究。

                              1)@EnableMongoRepositories其实挺简单就能用上,之前是别的地方搞错了。
                              2) 我别的项目都是直接上springboot全套,才注意到openfeign自动实现是依赖spring-cloud,打算不引入了。手动构造openfeign本身工作量也不大。

                              1 条回复 最后回复 回复 引用 0
                              • 1 / 1
                              • First post
                                Last post
                              Powered by Mamoe Technologies & NodeBB | 友情链接 | 服务监控 | Contact