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. 插件化架构(动态发现和注册组件)
相关推荐
Livingbody17 分钟前
FastMCP In Action之 Server详解
后端
GetcharZp1 小时前
C++ Boost 从入门到精通:让你的代码飞起来
c++·后端
北'辰1 小时前
DeepSeek智能考试系统智能体
前端·后端·架构·开源·github·deepseek
hrrrrb2 小时前
【Spring Boot 快速入门】八、登录认证(二)统一拦截
hive·spring boot·后端
_風箏3 小时前
OpenSSH【安装 03】远程代码执行漏洞CVE-2024-6387修复(cp: 无法创建普通文件“/usr/sbin/sshd“:文本文件忙问题处理)
后端
用户89535603282203 小时前
Gin 框架核心架构解析
后端·go
我是哪吒4 小时前
分布式微服务系统架构第164集:架构懂了就来了解数据库存储扩展千亿读写
后端·面试·github
UrbanJazzerati4 小时前
PowerShell 自动化实战:自动化为 Git Staged 内容添加 Issue 注释标记
后端·面试·shell
橙序员小站4 小时前
通过trae开发你的第一个Chrome扩展插件
前端·javascript·后端
wave7774 小时前
feign的bean创建过程-底层请求过程-源码走读
后端·面试