因此,您需要即时声明新的bean,并将它们注入Spring的应用程序上下文中,就好像它们只是普通的Bean一样,这意味着它们必须受到代理,后处理等的影响,即它们必须受Spring Bean生命周期的影响。
请参阅BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry()
方法javadocs。这正是您所需要的,因为它允许您在加载正常Bean定义之后但在实例化任何单个Bean之前修改Spring的应用程序上下文。
@Configuration
public class ConfigLoader implements BeanDefinitionRegistryPostProcessor {
private final List<String> configurations;
public ConfigLoader() {
this.configurations = new LinkedList<>();
// TODO Get names of different configurations, just the names!
// i.e. You could manually read from some config file
// or scan classpath by yourself to find classes
// that implement MyConfiguration interface.
// (You can even hardcode config names to start seeing how this works)
// Important: you can't autowire anything yet,
// because Spring has not instantiated any bean so far!
for (String readConfigurationName : readConfigurationNames) {
this.configurations.add(readConfigurationName);
}
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// iterate over your configurations and create the beans definitions it needs
for (String configName : this.configurations) {
this.quartzConfiguration(configName, registry);
this.quartzModule(configName, registry);
this.healthCheck(configName, registry);
// etc.
}
}
private void quartzConfiguration(String configName, BeanDefinitionRegistry registry) throws BeansException {
String beanName = configName + "_QuartzConfiguration";
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(QuartzConfiguration.class).setLazyInit(true);
// TODO Add what the bean needs to be properly initialized
// i.e. constructor arguments, properties, shutdown methods, etc
// BeanDefinitionBuilder let's you add whatever you need
// Now add the bean definition with given bean name
registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
}
private void quartzModule(String configName, BeanDefinitionRegistry registry) throws BeansException {
String beanName = configName + "_QuartzModule";
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(QuartzModule.class).setLazyInit(true);
builder.addConstructorArgReference(configName + "_QuartzConfiguration"); // quartz configuration bean as constructor argument
// Now add the bean definition with given bean name
registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
}
private void healthCheck(String configName, BeanDefinitionRegistry registry) throws BeansException {
String beanName = configName + "_HealthCheck";
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(HealthCheck.class).setLazyInit(true);
// TODO Add what the bean needs to be properly initialized
// i.e. constructor arguments, properties, shutdown methods, etc
// BeanDefinitionBuilder let's you add whatever you need
// Now add the bean definition with given bean name
registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
}
// And so on for other beans...
}
这有效地声明了您需要的bean,并将它们注入Spring的应用程序上下文中,每个配置都有一组bean。您必须依靠一些命名模式,然后在需要时按名称自动连接bean:
@Service
public class MyService {
@Resource(name="config1_QuartzConfiguration")
private QuartzConfiguration config1_QuartzConfiguration;
@Resource(name="config1_QuartzModule")
private QuartzModule config1_QuartzModule;
@Resource(name="config1_HealthCheck")
private HealthCheck config1_HealthCheck;
...
}
笔记:
-
如果您通过从文件中手动读取配置名称,请使用Spring的ClassPathResource.getInputStream()。
。
-
如果您自己扫描类路径,我强烈建议您使用令人惊叹的反射库。
-
您必须手动设置每个 Bean 定义的所有属性和依赖项。每个Bean定义都独立于其他Bean定义,即您无法重用它们,将它们一个地设置在另一个内部,等等。把它们想象成以旧的XML方式声明bean。
-
检查BeanDefinitionBuilder javadocs和GenericBeanDefinition javadocs以获取更多详细信息。