当前位置: 首页 > 知识库问答 >
问题:

有没有一种方法可以让一个Spring程序在运行时加载其他Spring jar作为插件?

刘丰羽
2023-03-14

我们想制作一个基于spring的插件式主程序。主程序可以加载其他Spring jar和非Spring jar作为插件。每个插件都基于IPlugin,插件的“IPlugin”类与主程序的“IPlugin”类相同。我们通过“URLClassLoader”使非spring插件工作,但这种方式不适用于spring插件。在“TestPlugin”项目中,名为“PluginTest”和“SpringApplication”的实现。运行(PluginTest.class,args);'在函数“init(String[])”中加载类“PluginTest”发生ClassNotFoundException(spring jars结构的原因)。

String pluginClassName =  "com.example.demo.PluginTest";
c = newClassLoader.loadClass(pluginClassName);

因此,我们替换pom'plugins'部分如下:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <version>3.1.0</version>
    <configuration>
        <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
        <finalName>${project.artifactId}-${project.version}</finalName>
        <appendAssemblyId>false</appendAssemblyId>
        <attach>false</attach>
        <archive>
            <manifest>
                <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
            </manifest>
        </archive>
    </configuration>
    <executions>
        <execution>
            <id>make-assembly</id>
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
        </execution>
    </executions>
</plugin>

但是,我们得到了另一个错误'引起的:java.lang.NoClassDefFoundError: com/zaxxer/hikari/HikariConfig'(测试项目中使用的JDBC)。我不知道如何在运行时正确加载其他Spring罐。

插件加载器完整代码

@Component
public class Initializer implements ApplicationRunner
{
    @Override
    public void run(ApplicationArguments args)
    {
        String jarPath = "e:/tmp/demo-0.0.1-SNAPSHOT.jar";
        File file = new File(jarPath);
        IPlugin p;

        try
        {

            ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
            URLClassLoader newClassLoader = new URLClassLoader(new URL[]{file.toURI().toURL()}, oldClassLoader);
            Thread.currentThread().setContextClassLoader(newClassLoader);

            String pluginClassName =  "com.example.demo.PluginTest";
            Class<?> c = newClassLoader.loadClass(pluginClassName);
            Object pluginTest = c.newInstance();
            p = (IPlugin)pluginTest;
            p.init(new String[]{
                    "--spring.config.location=e:/tmp/application.properties"
            });
        }
        catch (Exception e)
        {
            System.out.println(e);
            e.printStackTrace();
        }
    }
}

谢啦!

共有1个答案

周通
2023-03-14

简而言之,如果您的需求是在运行时加载外部JAR并用它扩展spring应用程序上下文,那么这是不可能的,原因有两个:

  • Spring应用程序上下文是在应用程序启动时通过扫描类路径、实例化所有bean并将它们相互连接(另外,还要做很多花哨的事情)来构建的。一旦设置完毕,该应用程序上下文基本上是静态的,不会重新评估

简而言之,Spring不是为这种动态性而设计的。如果这是您真正需要的,请考虑更适合这种需求的应用程序平台。OSGI(Spring DM构建于OSGI之上)可能是一种解决方案,但需要注意的是,构建OSGI应用程序涉及到巨大的复杂性和开销,该平台需要应用程序开发人员来解决上述挑战。

相反,我真的建议评估您是否可以使用一个模型,它可以在没有动态代码加载的情况下运行,因为这会让事情变得容易得多。例如,Spring内置了一个非常有用的自动配置系统,这需要绝对最小的开销。不过,必要的是您的库在运行时出现在类路径中。有关更多详细信息,您可以阅读此处的留档。

 类似资料:
  • 我知道一个测试可以通过运行来运行,在sbt中, 有没有办法告诉sbt/scalatest在没有标签的情况下运行单个测试?例如: 这意味着“在类中运行第二个测试。不管它是什么”。我们有一堆测试,没有人费心去标记它们,那么有没有办法在没有标签的情况下运行单个测试?

  • 问题内容: 假设我有以下代码: 这段代码的问题在于,协程内部的循环永远不会完成第一次迭代,而大小会不断增加。 为什么会这样发生,我该怎么解决? 我无法摆脱单独的线程,因为在我的真实代码中,我使用了单独的线程与串行设备进行通信,而且我还没有找到使用的方法。 问题答案: 不是线程安全的,因此您不能直接在多个线程中直接使用它。相反,您可以使用,它是提供线程感知队列的第三方库: 还有(全披露:我写了它),

  • 给定项目Reactor的通量或Mono,有没有办法让通量或Mono打印出操作链的样子。例如,下面给出了代码。 有没有办法让flux打印出处理管道中链接的所有操作员的列表?一些漂亮的ascii格式文本或大理石图? printTheFlux(通量)应该制作一个很好的打印输出,显示上面示例中所有运算符的结构。我不期望在lambda中生成代码只是一种查看哪些运算符链接在一起的方式。

  • 问题内容: 我有一个现有的JPA(EclipseLink)项目,其中所需的行为是,如果在实体的字段中给出空值,则不应保留该空值。 用例是我们可能会从外部来源对这些实体进行一些部分更新。这些来源可能会给我们一个空值,这并不意味着“使该字段无效”,而是“我没有这个值”。 是否有注释,模式或其他工具可用于在setter中自动执行空检查,或告诉JPA不要保留空值??? 我可以检查每个实体中的每个设置器,然

  • 问题内容: 我想在我的sails.js应用程序中用猫鼬代替吃水线。我正在寻找执行此操作的正确方法,但是我没有在文档中看到操作方法。谁能解释该怎么做? 问题答案: 通过.sailsrc定义替代 您可以通过在项目根目录中定义的配置覆盖来实现。基本上,您必须阻止当前标记为“ 钩子” 的整个“水线”初始化。在.sailsrc中: 您还必须禁用该挂钩- 这取决于挂钩。源中的相关行:v0.10,v0.9.8。

  • 作为一个学校项目,我正在开发一个坦克游戏,我正在努力使它尽可能的用户友好(比如可定制的按键绑定、显示设置)。然而,我不希望游戏窗口失去它的比例,所以我想我会在游戏窗口的两侧添加边框,以支持宽屏幕。 我附上了一张图片来说明我在寻找什么: 因此,为了让它工作,我需要一种制作“屏幕层”的方法。基本层是整个屏幕,在屏幕两侧添加了一些图形和显示分数的字体。然后,第二层将呈现在屏幕的中间,这将是游戏窗口,其宽