From a7457d08d63cbfee9e24f380b5b98bec29149fca Mon Sep 17 00:00:00 2001 From: trang Date: Thu, 23 Nov 2017 17:39:29 +0800 Subject: [PATCH] 1.1.3 --- .../src/main/resources/application.yml | 4 +- .../trang/druid/example/test/NormalTest.java | 20 +-- .../autoconfigure/DruidAutoConfiguration.java | 29 ++++ .../DruidDataSourceConfiguration.java | 140 ++++++++++++------ .../druid/autoconfigure/util/CharMatcher.java | 4 + 5 files changed, 134 insertions(+), 63 deletions(-) diff --git a/druid-spring-boot-example/druid-spring-boot-mybatis-example/src/main/resources/application.yml b/druid-spring-boot-example/druid-spring-boot-mybatis-example/src/main/resources/application.yml index a07b8cc..0c60b6c 100644 --- a/druid-spring-boot-example/druid-spring-boot-mybatis-example/src/main/resources/application.yml +++ b/druid-spring-boot-example/druid-spring-boot-mybatis-example/src/main/resources/application.yml @@ -97,10 +97,10 @@ spring: druid: # 继承 spring.datasource.druid 前缀的配置,同时可以自定义配置,若名称相同则覆盖父配置 data-sources: - master-data-source: + master: max-active: 50 max-open-prepared-statements: 50 - slave-data-source: + slave: max-active: 25 max-open-prepared-statements: 25 diff --git a/druid-spring-boot-example/druid-spring-boot-mybatis-example/src/test/java/com/github/trang/druid/example/test/NormalTest.java b/druid-spring-boot-example/druid-spring-boot-mybatis-example/src/test/java/com/github/trang/druid/example/test/NormalTest.java index 64643d1..f0a837b 100644 --- a/druid-spring-boot-example/druid-spring-boot-mybatis-example/src/test/java/com/github/trang/druid/example/test/NormalTest.java +++ b/druid-spring-boot-example/druid-spring-boot-mybatis-example/src/test/java/com/github/trang/druid/example/test/NormalTest.java @@ -56,23 +56,9 @@ public class NormalTest { @Test public void hashcode() { - Hash hash = new Hash(); - Hash hash2 = new Hash(); - System.out.println(hash == hash2); - System.out.println(hash.equals(hash2)); + String camelAlias = "XxXDatasource"; + String alias = camelAlias.substring(0, camelAlias.toLowerCase().indexOf("DataSource".toLowerCase())); + System.out.println(alias); } - class Hash { - @Override - public int hashCode() { - return 1; - } - - @Override - public boolean equals(Object obj) { - return true; - } - } - - } \ No newline at end of file diff --git a/druid-spring-boot/druid-spring-boot-autoconfigure/src/main/java/com/github/trang/druid/autoconfigure/DruidAutoConfiguration.java b/druid-spring-boot/druid-spring-boot-autoconfigure/src/main/java/com/github/trang/druid/autoconfigure/DruidAutoConfiguration.java index 8753c7e..9ad3d08 100644 --- a/druid-spring-boot/druid-spring-boot-autoconfigure/src/main/java/com/github/trang/druid/autoconfigure/DruidAutoConfiguration.java +++ b/druid-spring-boot/druid-spring-boot-autoconfigure/src/main/java/com/github/trang/druid/autoconfigure/DruidAutoConfiguration.java @@ -9,9 +9,12 @@ import com.alibaba.druid.filter.stat.StatFilter; import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.wall.WallConfig; import com.alibaba.druid.wall.WallFilter; +import com.github.trang.druid.autoconfigure.datasource.DruidDataSource2; import com.github.trang.druid.autoconfigure.properties.DruidDataSourceProperties; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; @@ -20,8 +23,14 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.Import; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import static com.github.trang.druid.autoconfigure.properties.DruidDataSourceProperties.*; /** @@ -101,4 +110,24 @@ public class DruidAutoConfiguration { return new CommonsLogFilter(); } + @Bean + @ConditionalOnBean(DruidDataSource.class) + public Map dataSourceMap(ConfigurableListableBeanFactory beanFactory) { + return new HashMap<>(beanFactory.getBeansOfType(DruidDataSource2.class)); + } + + /** + * 为了便于使用,增加数据源集合,可直接注入使用 + * 如需使用 Set、Array 请注入 Set 或 DruidDataSource2[] + * + * @param dataSourceMap 多数据源 + * @return List dataSourceList + */ + @Bean + @ConditionalOnBean(name = "dataSourceMap") + @DependsOn("dataSourceMap") + public List dataSourceList(Map dataSourceMap) { + return new ArrayList<>(dataSourceMap.values()); + } + } \ No newline at end of file diff --git a/druid-spring-boot/druid-spring-boot-autoconfigure/src/main/java/com/github/trang/druid/autoconfigure/DruidDataSourceConfiguration.java b/druid-spring-boot/druid-spring-boot-autoconfigure/src/main/java/com/github/trang/druid/autoconfigure/DruidDataSourceConfiguration.java index 28f8c87..6eafae1 100644 --- a/druid-spring-boot/druid-spring-boot-autoconfigure/src/main/java/com/github/trang/druid/autoconfigure/DruidDataSourceConfiguration.java +++ b/druid-spring-boot/druid-spring-boot-autoconfigure/src/main/java/com/github/trang/druid/autoconfigure/DruidDataSourceConfiguration.java @@ -1,22 +1,21 @@ package com.github.trang.druid.autoconfigure; -import com.github.trang.druid.autoconfigure.datasource.DruidDataSource2; -import com.github.trang.druid.autoconfigure.properties.DruidDataSourceProperties; -import com.github.trang.druid.autoconfigure.util.CharMatcher; +import com.alibaba.druid.pool.DruidDataSource; import com.github.trang.druid.autoconfigure.DruidDataSourceConfiguration.DataSourceImportSelector; +import com.github.trang.druid.autoconfigure.datasource.DruidDataSource2; +import com.github.trang.druid.autoconfigure.util.CharMatcher; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryAware; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.boot.bind.PropertySourcesBinder; import org.springframework.boot.bind.RelaxedPropertyResolver; import org.springframework.context.EnvironmentAware; -import org.springframework.context.annotation.*; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; +import org.springframework.context.annotation.ImportSelector; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotationMetadata; @@ -24,18 +23,25 @@ import org.springframework.core.type.AnnotationMetadata; import java.util.Map; /** + * Druid 数据源配置 + * * @author trang */ -@Import({DataSourceImportSelector.class}) +@Import(DataSourceImportSelector.class) @Slf4j public class DruidDataSourceConfiguration { - public static class SingleDataSourceRegister implements ImportBeanDefinitionRegistrar { + /** + * 单数据源注册 + * + * @author trang + */ + static class SingleDataSourceRegister implements ImportBeanDefinitionRegistrar { static final String BEAN_NAME = "dataSource"; @Override - public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { + public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { if (!registry.containsBeanDefinition(BEAN_NAME)) { BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(DruidDataSource2.class) .setInitMethodName("init") @@ -47,48 +53,62 @@ public class DruidDataSourceConfiguration { } } - public static class DynamicDataSourceRegister implements ImportBeanDefinitionRegistrar, BeanFactoryAware, EnvironmentAware { + /** + * 多数据源注册 + * + * @author trang + */ + static class DynamicDataSourceRegister implements ImportBeanDefinitionRegistrar, EnvironmentAware { - private DruidDataSourceProperties druidDataSourceProperties; - private DefaultListableBeanFactory beanFactory; - private ConfigurableEnvironment environment; + private static final String BEAN_SUFFIX = "DataSource"; + private RelaxedPropertyResolver resolver; @Override - public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { - druidDataSourceProperties.getDataSources().forEach((dataSourceName, dataSourceConfig) -> { - // 构造 BeanDefinition,通过 DruidDataSource2 实现继承 'spring.datasource.druid' 的配置 - BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(DruidDataSource2.class) - .setInitMethodName("init") - .setDestroyMethodName("close") - .getBeanDefinition(); - // 注册 BeanDefinition - String beanName = CharMatcher.separatedToCamel().apply(dataSourceName); - registry.registerBeanDefinition(beanName, beanDefinition); - // 将 'spring.datasource.druid.data-sources.${name}' 的配置绑定到 Bean - DruidDataSource2 dataSource = beanFactory.getBean(beanName, DruidDataSource2.class); - PropertySourcesBinder propertySourcesBinder = new PropertySourcesBinder(environment); - propertySourcesBinder.bindTo("spring.datasource.druid.data-sources." + dataSourceName, dataSource); - log.debug("druid {}-data-source init...", dataSourceName); - }); - } - - @Autowired - public void setDruidDataSourceProperties(DruidDataSourceProperties properties) { - this.druidDataSourceProperties = properties; - } - - @Override - public void setBeanFactory(BeanFactory beanFactory) throws BeansException { - this.beanFactory = (DefaultListableBeanFactory) beanFactory; + public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { + resolver.getSubProperties("").keySet().stream() + .map(key -> key.substring(0, key.indexOf("."))) + .distinct() + .forEach(dataSourceName -> { + // 构造 BeanDefinition,通过 DruidDataSource2 实现继承 'spring.datasource.druid' 的配置 + BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(DruidDataSource2.class) + .setInitMethodName("init") + .setDestroyMethodName("close") + .getBeanDefinition(); + // 注册 BeanDefinition + registry.registerBeanDefinition(dataSourceName, beanDefinition); + // 注册驼峰别名 + String camelAlias = CharMatcher.separatedToCamel().apply(dataSourceName); + registry.registerAlias(dataSourceName, camelAlias); + // 注册以 DataSource 为后缀的别名 + String otherAlias; + if (camelAlias.toLowerCase().endsWith(BEAN_SUFFIX.toLowerCase())) { + if (!camelAlias.endsWith(BEAN_SUFFIX)) { + otherAlias = camelAlias.substring(0, camelAlias.toLowerCase().indexOf(BEAN_SUFFIX.toLowerCase())); + otherAlias = otherAlias + BEAN_SUFFIX; + registry.registerAlias(dataSourceName, otherAlias); + } + } else { + otherAlias = camelAlias + BEAN_SUFFIX; + registry.registerAlias(dataSourceName, otherAlias); + } + log.debug("druid {}-data-source init...", dataSourceName); + }); } @Override public void setEnvironment(Environment environment) { - this.environment = (ConfigurableEnvironment) environment; + this.resolver = new RelaxedPropertyResolver(environment, "spring.datasource.druid.data-sources."); } } + /** + * 数据源选择器 + * 当配置文件中存在 spring.datasource.druid.data-sources 属性时为多数据源 + * 不存在则为单数据源 + * + * @author trang + */ static class DataSourceImportSelector implements ImportSelector, EnvironmentAware { private ConfigurableEnvironment environment; @@ -98,9 +118,41 @@ public class DruidDataSourceConfiguration { RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(environment, "spring.datasource.druid."); Map properties = resolver.getSubProperties("data-sources"); if (properties.isEmpty()) { - return new String[]{DruidDataSourceProperties.class.getName(), SingleDataSourceRegister.class.getName()}; + return new String[]{SingleDataSourceRegister.class.getName()}; } - return new String[]{DruidDataSourceProperties.class.getName(), DynamicDataSourceRegister.class.getName()}; + return new String[]{DynamicDataSourceRegister.class.getName(), + DataSourceBeanPostProcessor.class.getName()}; + } + + @Override + public void setEnvironment(Environment environment) { + this.environment = (ConfigurableEnvironment) environment; + } + + } + + /** + * DataSource Bean 处理器 + * + * @author trang + */ + static class DataSourceBeanPostProcessor implements BeanPostProcessor, EnvironmentAware { + + private ConfigurableEnvironment environment; + + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + if (bean instanceof DruidDataSource) { + // 将 'spring.datasource.druid.data-sources.${name}' 的配置绑定到 Bean + PropertySourcesBinder binder = new PropertySourcesBinder(environment); + binder.bindTo("spring.datasource.druid.data-sources." + beanName, bean); + } + return bean; + } + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + return bean; } @Override diff --git a/druid-spring-boot/druid-spring-boot-autoconfigure/src/main/java/com/github/trang/druid/autoconfigure/util/CharMatcher.java b/druid-spring-boot/druid-spring-boot-autoconfigure/src/main/java/com/github/trang/druid/autoconfigure/util/CharMatcher.java index e6ab1f1..25afce9 100644 --- a/druid-spring-boot/druid-spring-boot-autoconfigure/src/main/java/com/github/trang/druid/autoconfigure/util/CharMatcher.java +++ b/druid-spring-boot/druid-spring-boot-autoconfigure/src/main/java/com/github/trang/druid/autoconfigure/util/CharMatcher.java @@ -18,6 +18,10 @@ public final class CharMatcher { return Manipulation.SEPARATED_TO_CAMELCASE; } + public static Manipulation camelToHyphen() { + return Manipulation.CAMELCASE_TO_HYPHEN; + } + public static enum Manipulation { NONE {