Spring扩展接口(五)- 实例2自定义插件

好的!我用两个实际的代码例子来演示 @Import 的第二种(动态选择)和第三种(高级自定义)用法,保证你一看就懂!


示例1:动态选择配置(ImportSelector

场景:根据当前操作系统(Windows/Linux)自动加载不同的配置

java 复制代码
// 1. 定义两个不同的配置类
@Configuration
public class WindowsConfig {
    @Bean
    public CommandRunner windowsRunner() {
        return () -> System.out.println("Running dir command (Windows)");
    }
}

@Configuration
public class LinuxConfig {
    @Bean
    public CommandRunner linuxRunner() {
        return () -> System.out.println("Running ls command (Linux)");
    }
}

// 2. 实现智能选择器
public class OsImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata metadata) {
        String os = System.getProperty("os.name").toLowerCase();
        if (os.contains("win")) {
            return new String[]{WindowsConfig.class.getName()}; // 返回Windows配置类全限定名
        } else {
            return new String[]{LinuxConfig.class.getName()};   // 返回Linux配置类全限定名
        }
    }
}

// 3. 使用动态导入
@Configuration
@Import(OsImportSelector.class) // 关键!动态选择配置
public class AppConfig {
}

// 4. 测试
public static void main(String[] args) {
    ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    CommandRunner runner = context.getBean(CommandRunner.class);
    runner.run(); // 输出取决于操作系统!
}

效果

  • 在 Windows 下运行 → 执行 dir 命令逻辑
  • 在 Linux 下运行 → 执行 ls 命令逻辑

示例2:高级自定义注册(ImportBeanDefinitionRegistrar

场景 :动态注册所有实现了 MyPlugin 接口的类(模拟插件系统)

java 复制代码
// 1. 定义插件接口
public interface MyPlugin {
    void execute();
}

// 2. 实现两个插件
public class LogPlugin implements MyPlugin {
    @Override
    public void execute() {
        System.out.println("记录日志...");
    }
}

public class EmailPlugin implements MyPlugin {
    @Override
    public void execute() {
        System.out.println("发送邮件...");
    }
}

// 3. 实现动态注册器
public class PluginRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata,
            BeanDefinitionRegistry registry) {
        // 扫描包路径下所有实现MyPlugin的类
        ClassPathScanningCandidateComponentProvider scanner =
                new ClassPathScanningCandidateComponentProvider(false);
        scanner.addIncludeFilter(new AssignableTypeFilter(MyPlugin.class));

        for (BeanDefinition bd : scanner.findCandidateComponents("com.example")) {
            // 将每个插件类注册为Bean
            String beanName = StringUtils.uncapitalize(bd.getBeanClassName().substring(
                    bd.getBeanClassName().lastIndexOf(".") + 1));
            registry.registerBeanDefinition(beanName, bd);
        }
    }
}

// 4. 启用插件系统
@Configuration
@Import(PluginRegistrar.class) // 关键!动态注册插件
public class PluginConfig {
}

// 5. 测试
public static void main(String[] args) {
    ApplicationContext context = new AnnotationConfigApplicationContext(PluginConfig.class);
    Map<String, MyPlugin> plugins = context.getBeansOfType(MyPlugin.class);
    plugins.values().forEach(MyPlugin::execute); // 执行所有插件
}

效果

输出:

erlang 复制代码
记录日志...
发送邮件...

关键点总结

方式 实际应用场景 代码特征
ImportSelector 根据条件(环境、配置等)动态加载配置 实现 selectImports() 返回类全名
ImportBeanDefinitionRegistrar 需要完全控制Bean的注册过程 实现 registerBeanDefinitions() 手动注册

这两个例子展示了如何灵活使用 @Import 实现:

  1. 智能装配(自动适应不同环境)
  2. 插件化架构(动态发现和注册组件)
相关推荐
一点程序4 小时前
基于SpringBoot的选课调查系统
java·spring boot·后端·选课调查系统
怪兽源码6 小时前
基于SpringBoot的选课调查系统
java·spring boot·后端·选课调查系统
csdn_aspnet6 小时前
ASP.NET Core 中的依赖注入
后端·asp.net·di·.net core
昊坤说不出的梦7 小时前
【实战】监控上下文切换及其优化方案
java·后端
疯狂踩坑人7 小时前
【Python版 2026 从零学Langchain 1.x】(二)结构化输出和工具调用
后端·python·langchain
橘子师兄9 小时前
C++AI大模型接入SDK—ChatSDK封装
开发语言·c++·人工智能·后端
@ chen9 小时前
Spring事务 核心知识
java·后端·spring
一点技术10 小时前
基于SpringBoot的选课调查系统
java·spring boot·后端·选课调查系统
RANCE_atttackkk11 小时前
Springboot+langchain4j的RAG检索增强生成
java·开发语言·spring boot·后端·spring·ai·ai编程
好好研究12 小时前
Spring Boot - Thymeleaf模板引擎
java·spring boot·后端·thymeleaf