如何在 Spring Boot 中以编程方式创建 bean? [英] How do I create beans programmatically in Spring Boot?
问题描述
我有一个应用程序,其中包含许多列在 application.properties 中的数据源设置.我有一个加载这些设置的 @ConfigurationProperties
类.现在我想从这个 ConfigurationProperties
类中获取值,并使用它们即时创建数据源 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
属性为 null,CLIENT_DATASOURCES
我用 @PostConstruct
填充.
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 并要求 Spring Boot 向其中注入值?
How about creating your beans and ask Spring Boot to inject values into it?
类似的东西
@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
是该 的数据源密码数据源
).
Then, any setting in the ds.client1
namespace belongs to the first data source (i.e. ds.client1.password
is the data source password for that 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屋!