成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

徹底解耦!Spring Boot 實現外部 Jar 動態加載與熱插拔式擴展架構

開發 前端
通過動態構建類加載器、讀取?spring.factories?并手動注冊 Bean,我們成功在 Spring Boot 中實現了外部 Jar 的插件化加載。

在大型系統中,業務快速變化、功能可插拔、模塊可裁剪成為主流趨勢。為此,我們可以基于 Spring Boot 實現一種插件式架構,支持動態加載外部 Jar 并熱插拔模塊功能,進一步實現架構解耦、運行期擴展、服務熱更新等目標。

本文將帶你深入實現一套完整的插件機制,加載目錄 /usr/local/java/plugins 中的 Jar 包,并將其中的 Spring Bean 自動注入主工程上下文中。

架構目標與實現思路

核心目標可以拆解為兩個步驟:

  1. 將 Jar 加載到 JVM
  2. 讓 Spring 識別并注冊其中的 Bean

Spring Boot 本身對類加載器有一定擴展能力,再結合自定義加載器和 spring.factories,便可輕松實現這一機制。

項目結構概覽

plugin-loader-demo/
├── plugin-host/                      # 主工程,負責加載插件
│   ├── src/main/java/com/icoderoad/host/
│   │   └── PluginHostApplication.java
│   │   └── loader/
│   │       ├── PluginClassLoader.java
│   │       ├── PluginScanner.java
│   │       └── PluginRegistrar.java
├── plugin-user-center/              # 插件模塊:用戶中心功能
│   ├── src/main/java/com/icoderoad/plugins/user/
│   │   ├── UserService.java
│   │   └── UserAutoConfiguration.java
│   └── resources/META-INF/spring.factories

主工程 plugin-host 的 pom.xml

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.icoderoad</groupId>
  <artifactId>plugin-host</artifactId>
  <version>1.0.0</version>


  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>
  </dependencies>


  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
          <layout>ZIP</layout>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

插件模塊 plugin-user-center 的 pom.xml

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.icoderoad.plugins</groupId>
  <artifactId>plugin-user-center</artifactId>
  <version>1.0.0</version>


  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-autoconfigure</artifactId>
    </dependency>
  </dependencies>
</project>

插件加載器實現

PluginClassLoader:從目錄中加載外部 Jar

package com.icoderoad.host.loader;


public class PluginClassLoader extends URLClassLoader {
    public PluginClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
    }


    public static PluginClassLoader fromDirectory(String dirPath) throws IOException {
        File[] jars = new File(dirPath).listFiles(f -> f.getName().endsWith(".jar"));
        if (jars == null) return new PluginClassLoader(new URL[0], Thread.currentThread().getContextClassLoader());


        URL[] urls = Arrays.stream(jars)
            .map(file -> {
                try {
                    return file.toURI().toURL();
                } catch (MalformedURLException e) {
                    throw new RuntimeException(e);
                }
            })
            .toArray(URL[]::new);


        return new PluginClassLoader(urls, Thread.currentThread().getContextClassLoader());
    }
}

PluginScanner:讀取插件 Jar 中的 spring.factories

package com.icoderoad.host.loader;


public class PluginScanner {
    public static List<Class<?>> scanAutoConfigClasses(ClassLoader pluginClassLoader) throws IOException, ClassNotFoundException {
        List<Class<?>> result = new ArrayList<>();
        Enumeration<URL> resources = pluginClassLoader.getResources("META-INF/spring.factories");


        while (resources.hasMoreElements()) {
            try (InputStream input = resources.nextElement().openStream()) {
                Properties props = new Properties();
                props.load(input);
                String classList = props.getProperty(EnableAutoConfiguration.class.getName());
                if (classList != null) {
                    for (String className : classList.split(",")) {
                        result.add(Class.forName(className.trim(), true, pluginClassLoader));
                    }
                }
            }
        }
        return result;
    }
}

PluginRegistrar:注冊配置類到 Spring 容器

package com.icoderoad.host.loader;


public class PluginRegistrar {
    public static void registerPlugins(ConfigurableApplicationContext context, String pluginDir) throws Exception {
        PluginClassLoader loader = PluginClassLoader.fromDirectory(pluginDir);
        List<Class<?>> configClasses = PluginScanner.scanAutoConfigClasses(loader);


        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) context.getBeanFactory();
        AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(registry);
        reader.setBeanClassLoader(loader);


        for (Class<?> clazz : configClasses) {
            reader.register(clazz);
        }
    }
}

主程序入口整合插件加載邏輯

package com.icoderoad.host;


@SpringBootApplication
public class PluginHostApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(PluginHostApplication.class, args);
        try {
            PluginRegistrar.registerPlugins(context, "/usr/local/java/plugins");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

插件模塊:UserService + 自動配置類

// com.icoderoad.plugins.user.UserService
public class UserService {
    public String getUsername() {
        return "Plugin User";
    }
}


// com.icoderoad.plugins.user.UserAutoConfiguration
@Configuration
public class UserAutoConfiguration {
    @Bean
    public UserService userService() {
        return new UserService();
    }
}

插件 spring.factories 配置

路徑:src/main/resources/META-INF/spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.icoderoad.plugins.user.UserAutoConfiguration

插件測試驗證代碼

在主應用中通過注入判斷插件是否成功加載:

@Autowired(required = false)
private UserService userService;


@PostConstruct
public void init() {
    if (userService != null) {
        System.out.println("插件加載成功:" + userService.getUsername());
    } else {
        System.out.println("插件未加載!");
    }
}

總結

通過動態構建類加載器、讀取 spring.factories 并手動注冊 Bean,我們成功在 Spring Boot 中實現了外部 Jar 的插件化加載。

優點:

  • 插件 Jar 可獨立開發部署
  • 插件可運行期動態加載
  • 支持 Spring 自動配置機制
責任編輯:武曉燕 來源: 路條編程
相關推薦

2021-10-18 10:36:31

Spring Boot插件Jar

2021-10-18 12:04:22

Spring BootJava開發

2024-08-09 08:46:00

Springjar 包YAML

2022-07-13 08:36:57

MQ架構設計模式

2025-05-12 04:01:00

2021-07-30 13:46:59

前端架構插件

2022-09-02 08:23:12

軟件開發解耦架構

2025-02-11 07:55:45

2025-05-20 07:13:22

Spring異步解耦Event

2020-11-20 15:22:32

架構運維技術

2018-04-18 08:47:17

Alluxio構建存儲

2009-10-23 08:12:01

LinuxSCSI硬盤熱插拔

2017-12-26 15:52:31

MQ互聯網耦合

2017-11-15 09:32:27

解耦戰術架構

2024-10-18 08:00:00

SpringBoot框架開發

2023-11-20 23:02:36

Spring系統

2023-09-28 08:15:05

SpringBean加載

2025-06-06 01:00:00

Spring場景范式

2021-06-02 06:01:31

Java擴展Jar包

2018-01-01 06:41:44

耦合互聯網架構配置中心
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 综合久久99 | 欧美一区二区三区视频在线观看 | 日韩欧美在线不卡 | 精品国产91亚洲一区二区三区www | 久久99国产精品久久99果冻传媒 | 成人黄视频在线观看 | 中文字幕av一区二区三区 | 久久国产精品久久久久 | 少妇一区在线观看 | 毛片99 | 国产一级视频在线 | 人成精品 | 午夜精品影院 | 男人天堂网av | 成人网视频 | 日韩一二区在线观看 | 91不卡 | 国产精品美女久久久久aⅴ国产馆 | 免费一级大片 | 老头搡老女人毛片视频在线看 | 成人精品一区二区 | 国产免费福利小视频 | 在线观看av网站 | www久久99 | 免费麻豆视频 | 欧美在线国产精品 | 在线播放国产一区二区三区 | 欧美天堂 | 欧美色图综合网 | 久久成人18免费网站 | 一级大片网站 | 国产高清不卡 | 久草在线中文888 | 亚洲一区高清 | 综合久久av | av在线播放不卡 | 午夜视频在线 | 成人深夜福利 | 色橹橹欧美在线观看视频高清 | 中文字幕第十五页 | 久久久精品一区二区 |