All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.springleaf.cloud.discovery.config.datasource.ConfigDataSourceHandler Maven / Gradle / Ivy

There is a newer version: 1.0.1
Show newest version
package com.springleaf.cloud.discovery.config.datasource;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.springleaf.cloud.discovery.config.datasource.config.AbstractDataSourceProperties;
import com.springleaf.cloud.discovery.config.datasource.config.ConfigRuleProperties;
import com.springleaf.cloud.discovery.config.datasource.converter.JsonConverter;
import com.springleaf.cloud.discovery.config.datasource.datasource.AbstractDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.core.env.Environment;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 

*Config datasource handler dynamically registers the spring Bean * according to the configured datasource {@link ConfigRuleProperties}, *

*

* In addition, you can extend the {@link ConfigRuleLoadListener} listener to implement a custom extension * after the ConfigRuleProperties configuration is loaded. * And also extend the {@link RuleTypeCustomizer} interface to implement personalized extensions for different types of rules * *

*/ public class ConfigDataSourceHandler implements SmartInitializingSingleton { private final List loadListeners; private ObjectMapper objectMapper = new ObjectMapper(); private static final Logger log = LoggerFactory .getLogger(ConfigDataSourceHandler.class); private Map ruleTypeCustomizerMap = new ConcurrentHashMap<>(); private List dataTypeList = Arrays.asList("json", "xml"); private final String DATA_TYPE_FIELD = "dataType"; private final String CUSTOM_DATA_TYPE = "custom"; private final String CONVERTER_CLASS_FIELD = "converterClass"; private final String NAMESAPCE_FIELD = "namespace"; private final String RULETYPE_FIELD = "ruleType"; private final DefaultListableBeanFactory beanFactory; private final ConfigRuleProperties configRuleProperties; private final Environment env; public ConfigDataSourceHandler(DefaultListableBeanFactory beanFactory, ConfigRuleProperties configRuleProperties, Environment env, List ruleTypeCustomizers, List loadListeners) { this.beanFactory = beanFactory; this.configRuleProperties = configRuleProperties; this.env = env; this.loadListeners = loadListeners; objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); ruleTypeCustomizers.stream().forEach(it->{ ruleTypeCustomizerMap.put(it.supportRuleType(), it); }); } @Override public void afterSingletonsInstantiated() { fireConfigRuleLoadListener(loadListeners); configRuleProperties.getDatasource() .forEach((dataSourceName, dataSourceProperties) -> { try { List validFields = dataSourceProperties.getValidField(); if (validFields.size() != 1) { log.error("[Rule Starter] DataSource " + dataSourceName + " multi datasource active and won't loaded: " + dataSourceProperties.getValidField()); return; } AbstractDataSourceProperties abstractDataSourceProperties = dataSourceProperties .getFirstValidDataSourceProperties(); if (!ruleTypeCustomizerMap.containsKey(abstractDataSourceProperties.getRuleType())) { log.warn("未知的RuleType[" + abstractDataSourceProperties.getRuleType() + "]..."); return; } abstractDataSourceProperties.setEnv(env); abstractDataSourceProperties.preCheck(dataSourceName); registerBean(abstractDataSourceProperties, makeDataSourceName(dataSourceName, validFields.get(0))); } catch (Exception e) { log.error("[Rule Starter] DataSource " + dataSourceName + " build error: " + e.getMessage(), e); } }); } private String makeDataSourceName(String dataSourceName, String validField) { return dataSourceName + "-rule-" + validField + "-datasource"; } private void fireConfigRuleLoadListener(List loadListeners) { loadListeners.stream().forEach(it->{ it.onLoaded(configRuleProperties); }); } private void registerBean(final AbstractDataSourceProperties dataSourceProperties, String dataSourceName) { Map propertyMap = Arrays .stream(dataSourceProperties.getClass().getDeclaredFields()) .collect(HashMap::new, (m, v) -> { try { v.setAccessible(true); m.put(v.getName(), v.get(dataSourceProperties)); } catch (IllegalAccessException e) { log.error("[Rule Starter] DataSource " + dataSourceName + " field: " + v.getName() + " invoke error"); throw new RuntimeException( "[Rule Starter] DataSource " + dataSourceName + " field: " + v.getName() + " invoke error", e); } }, HashMap::putAll); propertyMap.put(CONVERTER_CLASS_FIELD, dataSourceProperties.getConverterClass()); propertyMap.put(DATA_TYPE_FIELD, dataSourceProperties.getDataType()); propertyMap.put(NAMESAPCE_FIELD, dataSourceProperties.getEnv().getProperty("spring.cloud.nacos.discovery.namespace","")); propertyMap.put(RULETYPE_FIELD, dataSourceProperties.getRuleType()); BeanDefinitionBuilder builder = BeanDefinitionBuilder .genericBeanDefinition(dataSourceProperties.getFactoryBeanName()); final RuleTypeCustomizer ruleTypeCustomizer = ruleTypeCustomizerMap.get(dataSourceProperties.getRuleType()); propertyMap.forEach((propertyName, propertyValue) -> { Field field = ReflectionUtils.findField(dataSourceProperties.getClass(), propertyName); if (null == field) { return; } if (DATA_TYPE_FIELD.equals(propertyName)) { String dataType = StringUtils.trimAllWhitespace(propertyValue.toString()); if (CUSTOM_DATA_TYPE.equals(dataType)) { try { if (StringUtils .isEmpty(dataSourceProperties.getConverterClass())) { throw new RuntimeException("[Rule Starter] DataSource " + dataSourceName + "dataType is custom, please set converter-class " + "property"); } // construct custom Converter with 'converterClass' // configuration and register String customConvertBeanName = "rule-" + dataSourceProperties.getConverterClass(); if (!this.beanFactory.containsBean(customConvertBeanName)) { this.beanFactory.registerBeanDefinition(customConvertBeanName, BeanDefinitionBuilder .genericBeanDefinition( Class.forName(dataSourceProperties .getConverterClass())) .getBeanDefinition()); } builder.addPropertyReference("converter", customConvertBeanName); } catch (ClassNotFoundException e) { log.error("[Rule Starter] DataSource " + dataSourceName + " handle " + dataSourceProperties.getClass().getSimpleName() + " error, class name: " + dataSourceProperties.getConverterClass()); throw new RuntimeException("[ConfigRule Starter] DataSource " + dataSourceName + " handle " + dataSourceProperties.getClass().getSimpleName() + " error, class name: " + dataSourceProperties.getConverterClass(), e); } } else { if (!dataTypeList.contains( StringUtils.trimAllWhitespace(propertyValue.toString()))) { throw new RuntimeException("[Rule Starter] DataSource " + dataSourceName + " dataType: " + propertyValue + " is not support now. please using these types: " + dataTypeList.toString()); } // converter type now support xml or json. // The bean name of these converters wrapped by builder.addPropertyValue("converter", new JsonConverter(objectMapper, ruleTypeCustomizer.getConvertClassType())); } } else if (CONVERTER_CLASS_FIELD.equals(propertyName)) { return; } else { // wired properties Optional.ofNullable(propertyValue) .ifPresent(v -> builder.addPropertyValue(propertyName, v)); } }); this.beanFactory.registerBeanDefinition(dataSourceName, builder.getBeanDefinition()); // init in Spring AbstractDataSource newDataSource = (AbstractDataSource) this.beanFactory .getBean(dataSourceName); ruleTypeCustomizer.customize(newDataSource); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy