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的动态注册。
应用场景
- 条件化注册Bean:通过判断热定条件,根据条件的真假动态注册Bean.
- 第三方库的集成:当需要将第三方库的某些组件集成到Spring容器时,可以使用其来注册这些组件的Bean定义;
- 自定义注解的处理:当需要处理自定义注解,并根据注解信息注册相应的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;
}
}
- 在某个配置类上使用
@Import
注解引入ImportBeanDefinitionRegistrar
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import(ConditionalBeanDefinitionRegistrar.class)
public class MainConfig {
// 主配置内容
}
- 设置配置属性
# application.properties
myapp.feature.enabled=true
- 使用Spring boot应用
当应用启动时,根据配置属性myapp.feature.enabled
的值,ConditionalBeanDefinitionRegistrar
会决定是否注册MyService
bean。
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);
}
}
发表回复