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. 插件化架构(动态发现和注册组件)
相关推荐
码事漫谈1 天前
智能体颠覆教育行业调研报告:英语、编程、语文、数学学科应用分析
后端
蓝-萧1 天前
使用Docker构建Node.js应用的详细指南
java·后端
码事漫谈1 天前
《C语言点滴》——笑着入门,扎实成长
后端
Tony Bai1 天前
【Go模块构建与依赖管理】09 企业级实践:私有仓库与私有 Proxy
开发语言·后端·golang
咖啡教室1 天前
每日一个计算机小知识:ICMP
后端·网络协议
间彧1 天前
OpenStack在混合云架构中通常扮演什么角色?
后端
咖啡教室1 天前
每日一个计算机小知识:IGMP
后端·网络协议
间彧1 天前
云原生技术栈中的核心组件(如Kubernetes、Docker)具体是如何协同工作的?
后端
清空mega1 天前
从零开始搭建 flask 博客实验(3)
后端·python·flask
努力的小郑1 天前
Elasticsearch 避坑指南:我在项目中总结的 14 条实用经验
后端·elasticsearch·性能优化