如何在Spring Boot中以编程方式创建bean? [英] How do I create beans programmatically in Spring Boot?

查看:95
本文介绍了如何在Spring Boot中以编程方式创建bean?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个应用程序,其中包含application.properties中列出的许多数据源设置。我有一个 @ConfigurationProperties 类来加载这些设置。现在我想从这个 ConfigurationProperties 类中获取值,并使用它们来动态创建DataSource bean。我尝试使用 @PostConstruct 并实现 BeanFactoryPostProcessor 。但是,使用 BeanFactoryPostProcessor ,处理似乎很早就发生了 - 在我的 ConfigurationProperties 类已经填充之前。如何使用Spring Boot动态读取属性并创建 DataSource bean?

I have an app that has a number of datasource settings listed in application.properties. I have a @ConfigurationProperties class that loads up these settings. Now I want to take the values from this ConfigurationProperties class and use them to create DataSource beans on-the-fly. I've tried using @PostConstruct and implementing BeanFactoryPostProcessor. However, with BeanFactoryPostProcessor, the processing seems to happen to early - before my ConfigurationProperties class has been populated. How can I read properties and create DataSource beans on the fly with Spring Boot?

这是我的application.properties看起来像:

Here's what my application.properties looks like:

ds.clients[0]=client1|jdbc:db2://server/client1
ds.clients[1]=client2,client3|jdbc:db2://server/client2
ds.clients[2]=client4|jdbc:db2://server/client4
ds.clients[3]=client5|jdbc:db2://server/client5

我的ConfigurationProperties类:

And my ConfigurationProperties class:

@Component
@ConfigurationProperties(prefix = "ds")
public class DataSourceSettings {
    public static Map<String, String> CLIENT_DATASOURCES = new LinkedHashMap<>();

    private List<String> clients = new ArrayList<>();

    public List<String> getClients() {
        return clients;
    }

    public void setClients(List<String> clients) {
        this.clients = clients;
    }

    @PostConstruct
    public void configure() {
        for (String client : clients) {
            // extract client name
            String[] parts = client.split("\\|");
            String clientName = parts[0];
            String url = parts[1];
            // client to datasource mapping
            String dsName = url.substring(url.lastIndexOf("/") + 1);
            if (clientName.contains(",")) {
                // multiple clients with same datasource
                String[] clientList = clientName.split(",");
                for (String c : clientList) {
                    CLIENT_DATASOURCES.put(c, dsName);
                }
            } else {
                CLIENT_DATASOURCES.put(clientName, dsName);
            }
        }
    }

在此结束时 @PostConstruct 方法,我想用这些设置创建 BasicDataSource 并将其添加到ApplicationContext。但是,如果我尝试通过实现 BeanFactoryPostProcessor 并实现 postProcessBeanFactory 来执行此操作,那么 clients property为null,我使用 @PostConstruct 填充 CLIENT_DATASOURCES 。 / p>

At the end of this @PostConstruct method, I'd like to create a BasicDataSource with these settings and add it to the ApplicationContext. However, if I try to do this by implement BeanFactoryPostProcessor and implementing postProcessBeanFactory, the clients property is null, as is the CLIENT_DATASOURCES that I've populated with @PostConstruct.

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    System.out.println("clients: " + CLIENT_DATASOURCES);
}

使用Spring Boot动态创建数据源的最佳方法是什么?

What's the best way to create datasources on-the-fly with Spring Boot?

推荐答案

如何创建bean并让Boot向其中注入值?

How about creating your beans and ask Boot to inject values into it?

类似

@Bean
@ConfigurationProperties("ds.client1")
public DataSource dataSource() {
    DataSourceBuilder.create().build();
}

@Bean
@ConfigurationProperties("ds.client2")
public DataSource dataSource() {
    DataSourceBuilder.create().build();
}

然后, ds.client1 <中的任何设置/ code> namespace属于第一个数据源(即 ds.client1.password 是该 DataSource的数据源密码)。

但也许你不知道你会有多少数据来源?这变得越来越复杂,特别是如果您需要在其他对象中注入这些动态数据源。如果您只需要按名称查找它们,您可以将它们自己注册为单身。下面是一个有效的示例

But maybe you don't know how much data sources you'll have? This is getting more complicated, especially if you need to inject those dynamic data sources in other objects. If you only need to lookup them by name, you could register them yourself as singletons. Here is an example that works

@ConfigurationProperties(prefix = "ds")
public class DataSourceSettings implements BeanFactoryAware {

    private List<String> clients = new ArrayList<>();

    private BeanFactory beanFactory;

    public List<String> getClients() {
        return clients;
    }

    public void setClients(List<String> clients) {
        this.clients = clients;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    @PostConstruct
    public void configure() {
        Map<String, String> clientDataSources = new HashMap<String, String>();
        for (String client : clients) {
            // extract client name
            String[] parts = client.split("\\|");
            String clientName = parts[0];
            String url = parts[1];
            // client to datasource mapping
            String dsName = url.substring(url.lastIndexOf("/") + 1);
            if (clientName.contains(",")) {
                // multiple clients with same datasource
                String[] clientList = clientName.split(",");
                for (String c : clientList) {
                    clientDataSources.put(c, url);
                }
            }
            else {
                 clientDataSources.put(clientName, url);
            }
        }
        Assert.state(beanFactory instanceof ConfigurableBeanFactory, "wrong bean factory type");
        ConfigurableBeanFactory configurableBeanFactory = (ConfigurableBeanFactory) beanFactory;
        for (Map.Entry<String, String> entry : clientDataSources.entrySet()) {
            DataSource dataSource = createDataSource(entry.getValue());
            configurableBeanFactory.registerSingleton(entry.getKey(), dataSource);
        }
    }

    private DataSource createDataSource(String url) {
        return DataSourceBuilder.create().url(url).build();
    }
}

请注意,这些bean仅 可通过bean名称查找。如果有效,请告诉我。

Note that those beans are only available by bean name lookup. Let me know if that works out for you.

这篇关于如何在Spring Boot中以编程方式创建bean?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆