当前位置: 首页 > 面试题库 >

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

穆文斌
2023-03-14
问题内容

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

这是我的application.properties的样子:

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类:

@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属性为null,就像CLIENT_DATASOURCES我填充的一样@PostConstruct

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

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


问题答案:

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

就像是

@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)。

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

@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名称查找获得。让我知道是否适合您。



 类似资料:
  • 下面是我的application.properties的样子: 和我的ConfigurationProperties类: 在这个方法的最后,我想创建一个具有这些设置的并将其添加到ApplicationContext中。但是,如果我试图通过实现并实现来实现这一点,则属性为null,我用填充的也是一样。 使用Spring Boot创建动态数据源的最佳方法是什么?

  • 我正尝试使用以下命令以编程方式创建:

  • 我想创建一个应用程序,它可以将屏幕行为记录为视频,并以编程方式保存在设备上。有人能帮我吗?

  • 问题内容: 是否有免费的库可根据图像序列创建MPEG(或任何其他简单的视频格式)? 它也必须在Linux上运行,并且最好具有Python绑定。 问题答案: 我知道有一个mencoder(是mplayer项目的一部分)和ffmpeg,它们都可以做到这一点。

  • 我有一个充满自定义视图的应用程序。当我尝试以编程方式创建FAB时,它会抛出一个错误 原因:java.lang.IllegalArgumentException:您需要在设计库中使用theme.AppCompat主题(或后代)。

  • 问题内容: 我尝试以编程方式实现UITableView,而不使用xib或Storyboards。这是我的代码: ViewController.swift MyTableViewController.swift 但是当我运行应用程序时,我得到的只是空表。在日志中,我看到了和的几行,但没有。如何修复此代码以获取包含6行文本的表格? 问题答案: 注意: 正如您提到的,您刚刚开始在中进行编程。我以编程方式