Spring Boot에서 프로그래밍 방식으로 콩을 작성하려면 어떻게 해야 하나요?
application.properties에 여러 데이터 소스 설정이 있는 앱을 가지고 있습니다.나는 가지고 있다@ConfigurationProperties
이 설정을 로드하는 클래스입니다.이제 여기서 값을 취하겠습니다.ConfigurationProperties
이를 사용하여 DataSource 빈을 즉시 만듭니다.사용해보았습니다.@PostConstruct
및 구현BeanFactoryPostProcessor
단,BeanFactoryPostProcessor
,처리가 너무 이른 것 같습니다 - 제 작업 전에ConfigurationProperties
클래스가 채워졌습니다.속성을 읽고 작성하려면 어떻게 해야 합니까?DataSource
스프링 부츠로 콩을 날릴까?
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
또한 Configuration Properties 클래스:
@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
method를 만듭니다.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을 사용하여 데이터 소스를 즉시 생성하는 가장 좋은 방법은 무엇입니까?
당신의 콩을 만들고 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();
}
}
이러한 콩은 빈 이름 검색을 통해서만 사용할 수 있습니다.괜찮으시다면 말씀해주세요.
당신의 사용 사례를 보여주기 위해 github에 샘플 프로젝트를 만들었습니다.
https://github.com/lhotari/dynamic-datasources
콩을 추가하기 위해 ImportBeanDefinitionRegistrar를 구현했습니다.EnvironmentAware를 구현하면 설정을 입수할 수 있습니다.목표를 달성하기 위한 다른 방법이 있을 수 있지만 GspAutoConfiguration에서 사용한 방법으로 콩을 동적으로 등록했습니다.GspAutoConfiguration을 사용하면 스프링 부트 어플리케이션에서 Grails GSP를 사용할 수 있습니다.
다이내믹 소스 샘플의 관련 컨피규레이션클래스는 다음과 같습니다.https://github.com/lhotari/dynamic-datasources/blob/master/src/main/groovy/sample/DynamicDataSourcesConfiguration.java
package sample;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.springframework.beans.FatalBeanException;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.boot.bind.PropertiesConfigurationFactory;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.jdbc.datasource.SingleConnectionDataSource;
import org.springframework.validation.BindException;
@Configuration
public class DynamicDataSourcesConfiguration implements ImportBeanDefinitionRegistrar, EnvironmentAware {
private ConfigurableEnvironment environment;
private static Map<String, Object> defaultDsProperties = new HashMap<String, Object>() {
{
put("suppressClose", true);
put("username", "sa");
put("password", "");
put("driverClassName", "org.h2.Driver");
}
};
@Override
public void setEnvironment(Environment environment) {
this.environment = (ConfigurableEnvironment)environment;
}
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
DataSourceSettings settings = resolveSettings();
for (Entry<String, String> entry : settings.clientDataSources().entrySet()) {
createDsBean(registry, entry.getKey(), entry.getValue());
}
}
private void createDsBean(BeanDefinitionRegistry registry, String beanName, String jdbcUrl) {
GenericBeanDefinition beanDefinition = createBeanDefinition(SingleConnectionDataSource.class);
beanDefinition.getPropertyValues().addPropertyValues(defaultDsProperties).addPropertyValue("url", jdbcUrl);
registry.registerBeanDefinition(beanName, beanDefinition);
}
private GenericBeanDefinition createBeanDefinition(Class<?> beanClass) {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(beanClass);
beanDefinition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_NO);
return beanDefinition;
}
private DataSourceSettings resolveSettings() {
DataSourceSettings settings = new DataSourceSettings();
PropertiesConfigurationFactory<Object> factory = new PropertiesConfigurationFactory<Object>(settings);
factory.setTargetName("ds");
factory.setPropertySources(environment.getPropertySources());
factory.setConversionService(environment.getConversionService());
try {
factory.bindPropertiesToTarget();
}
catch (BindException ex) {
throw new FatalBeanException("Could not bind DataSourceSettings properties", ex);
}
return settings;
}
}
언급URL : https://stackoverflow.com/questions/25160221/how-do-i-create-beans-programmatically-in-spring-boot
'it-source' 카테고리의 다른 글
모든 AJAX 요구에 대해 글로벌헤더를 설정할 수 있습니까? (0) | 2023.03.22 |
---|---|
WordPress 3.5 업로더에 새 이미지가 업로드되는 즉시 일부 코드를 실행하는 방법 (0) | 2023.03.22 |
Wordpress - $wpdb - > insert - MySQL NOW() (0) | 2023.03.22 |
SQL 쿼리의 이력을 확인합니다. (0) | 2023.03.22 |
Wordpress 플러그인 설정 데이터 (0) | 2023.03.22 |