首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在Spring Boot中以编程方式创建bean?

如何在Spring Boot中以编程方式创建bean?
EN

Stack Overflow用户
提问于 2014-08-06 20:19:41
回答 2查看 59.8K关注 0票数 31

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

下面是我的application.properties的样子:

代码语言:javascript
运行
复制
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类:

代码语言:javascript
运行
复制
@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中。但是,如果我尝试通过实现BeanFactoryPostProcessorpostProcessBeanFactory来完成此操作,则clients属性为null,正如我用@PostConstruct填充的CLIENT_DATASOURCES一样。

代码语言:javascript
运行
复制
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    System.out.println("clients: " + CLIENT_DATASOURCES);
}

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

EN

Stack Overflow用户

回答已采纳

发布于 2014-08-06 20:47:13

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

就像这样

代码语言:javascript
运行
复制
@Bean
@ConfigurationProperties("ds.client1")
public DataSource dataSourceClient1() {
    DataSourceBuilder.create().build();
}

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

然后,ds.client1名称空间中的任何设置都属于第一个数据源(即ds.client1.password是该DataSource的数据源密码)。

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

代码语言:javascript
运行
复制
@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名称查找获得的。如果这对你有帮助,请告诉我。

票数 24
EN
查看全部 2 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25160221

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档