Spring Boot: ImportBeanDefinitionRegistrar

在Spring Boot中,ImportBeanDefinitionRegistrar是一个允许动态注册bean定义的接口。它提供了一种机制,可以在运行时根据特定逻辑动态地向Spring上下文中注册bean。

ImportBeanDefinitionRegistrar的主要作用是允许开发者在应用上下文初始化时动态地注册一个活多个bean定义,这种能录可以用来实现灵活的配置管理,例如条件性bean注册、模块化配置、以及插件机制。

接口定义

public interface ImportBeanDefinitionRegistrar {
    void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
}
  • AnnotationMetadata importingClassMetadata表示使用了@Import注解的类的元数据;
  • BeanDefinitionRegistry registry表示允许注册新的bean定义。

当Spring容器启动并扫描到使用了@Import注解的类时,ImportBeanDefinitionRegistrar会被调用,并根据传入的元数据和注册器进行bean的动态注册。

应用场景

  1. 条件化注册Bean:通过判断热定条件,根据条件的真假动态注册Bean.
  2. 第三方库的集成:当需要将第三方库的某些组件集成到Spring容器时,可以使用其来注册这些组件的Bean定义;
  3. 自定义注解的处理:当需要处理自定义注解,并根据注解信息注册相应的Bean时,就可以派上用场。

示例1 : 条件性bean注册

1. 创建要注册的bean类

public class MyService {
    public void doSomething() {
        System.out.println("MyService is doing something!");
    }
}

平平无奇的一个类

2. 创建一个实现ImportBeanDefinitionRegistrar接口的类

该类会检查某个配置属性并根据其值决定是否注册MyService

import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.env.Environment;
import org.springframework.core.env.StandardEnvironment;

public class ConditionalBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    private Environment environment = new StandardEnvironment();

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // 读取配置属性
        boolean featureEnabled = Boolean.parseBoolean(environment.getProperty("myapp.feature.enabled", "false"));

        if (featureEnabled) {
            // 动态注册MyService bean
            RootBeanDefinition beanDefinition = new RootBeanDefinition(MyService.class);
            registry.registerBeanDefinition("myService", beanDefinition);
        }
    }

    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }
}
  1. 在某个配置类上使用@Import注解引入ImportBeanDefinitionRegistrar
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import(ConditionalBeanDefinitionRegistrar.class)
public class MainConfig {
    // 主配置内容
}
  1. 设置配置属性
# application.properties
myapp.feature.enabled=true
  1. 使用Spring boot应用

当应用启动时,根据配置属性myapp.feature.enabled的值,ConditionalBeanDefinitionRegistrar会决定是否注册MyServicebean。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
public class MySpringBootApplication {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(MySpringBootApplication.class, args);
        if (context.containsBean("myService")) {
            MyService myService = context.getBean(MyService.class);
            myService.doSomething();
        } else {
            System.out.println("MyService bean is not registered.");
        }
    }
}

示例2:实现模块化配置

1. 创建模块配置类

ModuleAConfig.java

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ModuleAConfig {
    @Bean
    public ModuleAService moduleAService() {
        return new ModuleAService();
    }
}

public class ModuleAService {
    public void perform() {
        System.out.println("Module A Service is performing!");
    }
}

ModuleBConfig.java

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ModuleBConfig {
    @Bean
    public ModuleBService moduleBService() {
        return new ModuleBService();
    }
}

public class ModuleBService {
    public void perform() {
        System.out.println("Module B Service is performing!");
    }
}

2. 实现ImportBeanDefinitionRegistrar接口

ModuleImportSelector.java

import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.core.env.Environment;
import org.springframework.core.env.EnvironmentCapable;
import org.springframework.context.EnvironmentAware;

public class ModuleImportSelector implements ImportBeanDefinitionRegistrar, EnvironmentAware {

    private Environment environment;

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        String modules = environment.getProperty("myapp.modules", "");

        if (modules.contains("moduleA")) {
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ModuleAConfig.class);
            registry.registerBeanDefinition("moduleAConfig", builder.getBeanDefinition());
        }

        if (modules.contains("moduleB")) {
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ModuleBConfig.class);
            registry.registerBeanDefinition("moduleBConfig", builder.getBeanDefinition());
        }
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }
}

3. 创建主配资类

MainConfig.java

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import(ModuleImportSelector.class)
public class MainConfig {
}

4. 创建Controller类

MyController.java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    @Autowired(required = false)
    private ModuleAService moduleAService;

    @Autowired(required = false)
    private ModuleBService moduleBService;

    @GetMapping("/perform")
    public String perform() {
        StringBuilder result = new StringBuilder();
        if (moduleAService != null) {
            moduleAService.perform();
            result.append("Module A Service performed. ");
        }
        if (moduleBService != null) {
            moduleBService.perform();
            result.append("Module B Service performed.");
        }
        return result.length() > 0 ? result.toString() : "No module services are available.";
    }
}

5. 配置属性

在application.properties文件中添加配置属性:

6. 启动应用

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MySpringBootApplication {
    public static void main(String[] args) {
        SpringApplication.run(MySpringBootApplication.class, args);
    }
}

示例3: 实现插件机制

1 创建插件接口

Plugin.java

public interface Plugin {
    void perform();
}

2 创建实现类

PlugunA.java

public class PluginA implements Plugin {
    @Override
    public void perform() {
        System.out.println("Plugin A is performing!");
    }
}

PluginB.java

public class PluginB implements Plugin {
    @Override
    public void perform() {
        System.out.println("Plugin B is performing!");
    }
}

3 穿件插件配置类

PluginAConfig.java

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class PluginAConfig {
    @Bean
    public Plugin pluginA() {
        return new PluginA();
    }
}

PluginBConfig.java

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class PluginBConfig {
    @Bean
    public Plugin pluginB() {
        return new PluginB();
    }
}

4 实现ImportBeanDefinitionRegistrar接口

import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.core.env.Environment;
import org.springframework.context.EnvironmentAware;

public class PluginImportRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {

    private Environment environment;

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        String plugins = environment.getProperty("myapp.plugins", "");

        if (plugins.contains("pluginA")) {
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(PluginAConfig.class);
            registry.registerBeanDefinition("pluginAConfig", builder.getBeanDefinition());
        }

        if (plugins.contains("pluginB")) {
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(PluginBConfig.class);
            registry.registerBeanDefinition("pluginBConfig", builder.getBeanDefinition());
        }
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }
}

5 创建主配资类

MainConfig.java

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import(PluginImportRegistrar.class)
public class MainConfig {
}

6 创建Controller

PluginController.java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class PluginController {

    private final List<Plugin> plugins;

    @Autowired
    public PluginController(List<Plugin> plugins) {
        this.plugins = plugins;
    }

    @GetMapping("/perform")
    public String perform() {
        StringBuilder result = new StringBuilder();
        for (Plugin plugin : plugins) {
            plugin.perform();
            result.append(plugin.getClass().getSimpleName()).append(" performed. ");
        }
        return result.length() > 0 ? result.toString() : "No plugins are available.";
    }
}

7 配置属性

application.properties文件中添加配置属性:

# application.properties
myapp.plugins=pluginA,pluginB

8 启动应用

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MySpringBootApplication {
    public static void main(String[] args) {
        SpringApplication.run(MySpringBootApplication.class, args);
    }
}

发表回复

您的电子邮箱地址不会被公开。