Spring-以编程方式生成一组bean

我有一个Dropwizard应用程序,需要为配置列表中的每个配置生成十几个bean。

像这样:

@Component

class MyModule {

@Inject

private MyConfiguration configuration;

@Bean

@Lazy

public QuartzModule quartzModule() {

return new QuartzModule(quartzConfiguration());

}

@Bean

@Lazy

public QuartzConfiguration quartzConfiguration() {

return this.configuration.getQuartzConfiguration();

}

@Bean

@Lazy

public HealthCheck healthCheck() throws SchedulerException {

return this.quartzModule().quartzHealthCheck();

}

}

我有多个MyConfiguration实例,都需要这样的bean。现在,我必须复制并粘贴这些定义,并为每个新配置重命名它们。

我可以以某种方式遍历我的配置类并为每个配置类生成一组bean定义吗?

我可以使用子类解决方案或任何类型安全的东西,而无需每次添加新服务时都复制并粘贴相同的代码并重命名方法。

编辑:我应该补充一点,我还有其他依赖于这些bean的组件(Collection<HealthCheck>例如,它们注入)。

回答:

你需要即时声明新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);

}

}

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;

...

}

笔记:

  1. 如果你要从文件中手动读取配置名称,请使用Spring的ClassPathResource.getInputStream()。

  2. 如果你自己扫描类路径,强烈建议你使用令人惊叹的Reflections库。

  3. 你必须为每个bean定义手动设置所有属性和依赖项。每个bean定义都独立于其他bean定义,即,你不能重用它们,也不能在另一个内部设置它们,等等。想想它们就像你在以旧的XML方式声明bean一样。

  4. 检查BeanDefinitionBuilder javadocs和GenericBeanDefinition javadocs以获得更多详细信息。

以上是 Spring-以编程方式生成一组bean 的全部内容, 来源链接: utcz.com/qa/411228.html

回到顶部