参考工程地址:https://gitee.com/proLeo/ray,分支dev-2.0,部分配置如下
druid starter和shardingsphere starter均使用较新版本 <properties> <mybatis-plus.version>3.1.0</mybatis-plus.version> <dubbo.starter.version>2.0.0</dubbo.starter.version> <druid.starter.version>1.1.22</druid.starter.version> <shardingsphere.version>4.1.0</shardingsphere.version> </properties> <!--dubbo--> <dependency> <groupId>com.alibaba.spring.boot</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>${dubbo.starter.version}</version> </dependency> <!--druid--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>${druid.starter.version}</version> </dependency> <!-- mybatis plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>${mybatis-plus.version}</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>${mybatis-plus.version}</version> </dependency> <!--shardingsphere--> <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-spring-boot-starter</artifactId> <version>${shardingsphere.version}</version> </dependency> <!-- 使用 XA 事务时,需要引入此模块 --> <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-transaction-xa-core</artifactId> <version>${shardingsphere.version}</version> </dependency> <!-- 使用 BASE 事务时,需要引入此模块 --> <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-transaction-base-seata-at</artifactId> <version>${shardingsphere.version}</version> </dependency> application-dev.yml配置,配置了分库分表和读写分离,mysql主从可以用项目中的docker/database/master-slave/docker-compose.yml快速搭建 spring: datasource: druid: # 连接池的配置信息 # 初始化大小,最小,最大 initial-size: 5 min-idle: 5 maxActive: 20 # 配置获取连接等待超时的时间 maxWait: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 timeBetweenEvictionRunsMillis: 60000 # 配置一个连接在池中最小生存的时间,单位是毫秒 minEvictableIdleTimeMillis: 300000 validationQuery: SELECT 1 FROM DUAL testWhileIdle: true testOnBorrow: false testOnReturn: false # 打开PSCache,并且指定每个连接上PSCache的大小 poolPreparedStatements: true maxPoolPreparedStatementPerConnectionSize: 20 web-stat-filter: enabled: true url-pattern: "/*" exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*" session-stat-enable: true session-stat-max-count: 1000 # 配置DruidStatViewServlet stat-view-servlet: enabled: true url-pattern: "/druid/*" # IP白名单(没有配置或者为空,则允许所有访问) # allow: 127.0.0.1,192.168.46.120 # IP黑名单 (存在共同时,deny优先于allow) # deny: 192.168.46.121 # 禁用HTML页面上的“Reset All”功能 reset-enable: false # 登录名 login-username: admin # 登录密码 login-password: 123456 dubbo: application: name: ray-iflow-rpc-service registry: zookeeper://192.168.125.161:2183 protocol: id: dubbo name: dubbo port: 20881 status: server #sharding配置 shardingsphere: dataSource: names: master0,master1,master0-slave1,master0-slave2,master1-slave1 master0: type: com.alibaba.druid.pool.DruidDataSource #自定义的配置项,因为type为DruidDataSource,需要特别配置filters,否则shardingsphere注入的DruidDataSource不含filters,不能实现相关的监控功能 filters: com.alibaba.druid.filter.stat.StatFilter,com.alibaba.druid.wall.WallFilter,com.alibaba.druid.filter.logging.Log4j2Filter url: jdbc:mysql://192.168.125.161:36005/iflow?autoReconnect=true&useUnicode=true&createDatabaseIfNotExist=true&characterEncoding=utf8&useSSL=false&serverTimezone=CTT username: root #使用了自定义的AES对称加密,启动时需要添加启动参数-Denc.key=${自定义的key},用ray-common中的AESUtil加密 #如果不需要去除enc:前缀即可 password: enc:jEhi6SfY38B7rIB9wrFZ1w== driver-class-name: com.mysql.cj.jdbc.Driver master0-slave1: type: com.alibaba.druid.pool.DruidDataSource filters: com.alibaba.druid.filter.stat.StatFilter,com.alibaba.druid.wall.WallFilter,com.alibaba.druid.filter.logging.Log4j2Filter url: jdbc:mysql://192.168.125.161:36006/iflow?autoReconnect=true&useUnicode=true&createDatabaseIfNotExist=true&characterEncoding=utf8&useSSL=false&serverTimezone=CTT username: root password: enc:jEhi6SfY38B7rIB9wrFZ1w== driver-class-name: com.mysql.cj.jdbc.Driver master0-slave2: type: com.alibaba.druid.pool.DruidDataSource filters: com.alibaba.druid.filter.stat.StatFilter,com.alibaba.druid.wall.WallFilter,com.alibaba.druid.filter.logging.Log4j2Filter url: jdbc:mysql://192.168.125.161:36007/iflow?autoReconnect=true&useUnicode=true&createDatabaseIfNotExist=true&characterEncoding=utf8&useSSL=false&serverTimezone=CTT username: root password: enc:jEhi6SfY38B7rIB9wrFZ1w== driver-class-name: com.mysql.cj.jdbc.Driver master1: type: com.alibaba.druid.pool.DruidDataSource filters: com.alibaba.druid.filter.stat.StatFilter,com.alibaba.druid.wall.WallFilter,com.alibaba.druid.filter.logging.Log4j2Filter url: jdbc:mysql://192.168.125.161:36008/iflow?autoReconnect=true&useUnicode=true&createDatabaseIfNotExist=true&characterEncoding=utf8&useSSL=false&serverTimezone=CTT username: root password: enc:jEhi6SfY38B7rIB9wrFZ1w== driver-class-name: com.mysql.cj.jdbc.Driver master1-slave1: type: com.alibaba.druid.pool.DruidDataSource filters: com.alibaba.druid.filter.stat.StatFilter,com.alibaba.druid.wall.WallFilter,com.alibaba.druid.filter.logging.Log4j2Filter url: jdbc:mysql://192.168.125.161:36009/iflow?autoReconnect=true&useUnicode=true&createDatabaseIfNotExist=true&characterEncoding=utf8&useSSL=false&serverTimezone=CTT username: root password: enc:jEhi6SfY38B7rIB9wrFZ1w== driver-class-name: com.mysql.cj.jdbc.Driver #分库分表 sharding: tables: operation: #此处有坑,如果配置了master-slave-rules则需要用其中配置的数据源 #actual-data-nodes: master$->{0..1}.operation_$->{0..1} #表规则 actual-data-nodes: db_master_$->{0..1}.operation_$->{0..1} #分库策略 database-strategy: inline: sharding-column: assess_status #和上面同样的坑,如果配置了master-slave-rules则需要用其中配置的数据源, #但是io.shardingsphere的starter确可以直接取datasource中的数据源 algorithm-expression: db_master_$->{assess_status%2} #分表策略 table-strategy: inline: sharding-column: id algorithm-expression: operation_$->{id % 2} # default-key-generator: # type: SnowflakeShardingKeyGenerator # column: id master-slave-rules: db_master_0: name: m0s2 master-data-source-name: master0 slave-data-source-names: master0-slave1,master0-slave2 db_master_1: name: m1s1 master-data-source-name: master1 slave-data-source-names: master1-slave1 props: sql: show: true server: tomcat: uri-encoding: UTF-8 port: 8085 mybatis-plus: datasource: dataSource mapper-locations: classpath*:/mappers/**/**Mapper.xml typeAliasesPackage: com.mrray.ray.iflow.dao.base.model configuration: cache-enabled: false 自定义sharding-jdbc配置替换sharding-jdbc-spring-boot-starter中的SpringBootConfiguration,不然要掉坑 package com.mrray.ray.common.sharding; import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure; import com.google.common.base.Preconditions; import com.mrray.ray.common.SpringContextUtil; import org.apache.shardingsphere.core.yaml.swapper.MasterSlaveRuleConfigurationYamlSwapper; import org.apache.shardingsphere.core.yaml.swapper.ShardingRuleConfigurationYamlSwapper; import org.apache.shardingsphere.core.yaml.swapper.impl.ShadowRuleConfigurationYamlSwapper; import org.apache.shardingsphere.encrypt.yaml.swapper.EncryptRuleConfigurationYamlSwapper; import org.apache.shardingsphere.shardingjdbc.api.EncryptDataSourceFactory; import org.apache.shardingsphere.shardingjdbc.api.MasterSlaveDataSourceFactory; import org.apache.shardingsphere.shardingjdbc.api.ShadowDataSourceFactory; import org.apache.shardingsphere.shardingjdbc.api.ShardingDataSourceFactory; import org.apache.shardingsphere.shardingjdbc.spring.boot.common.SpringBootPropertiesConfigurationProperties; import org.apache.shardingsphere.shardingjdbc.spring.boot.encrypt.EncryptRuleCondition; import org.apache.shardingsphere.shardingjdbc.spring.boot.encrypt.SpringBootEncryptRuleConfigurationProperties; import org.apache.shardingsphere.shardingjdbc.spring.boot.masterslave.MasterSlaveRuleCondition; import org.apache.shardingsphere.shardingjdbc.spring.boot.masterslave.SpringBootMasterSlaveRuleConfigurationProperties; import org.apache.shardingsphere.shardingjdbc.spring.boot.shadow.ShadowRuleCondition; import org.apache.shardingsphere.shardingjdbc.spring.boot.shadow.SpringBootShadowRuleConfigurationProperties; import org.apache.shardingsphere.shardingjdbc.spring.boot.sharding.ShardingRuleCondition; import org.apache.shardingsphere.shardingjdbc.spring.boot.sharding.SpringBootShardingRuleConfigurationProperties; import org.apache.shardingsphere.spring.boot.datasource.DataSourcePropertiesSetterHolder; import org.apache.shardingsphere.spring.boot.util.DataSourceUtil; import org.apache.shardingsphere.spring.boot.util.PropertyUtil; import org.apache.shardingsphere.transaction.spring.ShardingTransactionTypeScanner; import org.apache.shardingsphere.underlying.common.config.inline.InlineExpressionParser; import org.apache.shardingsphere.underlying.common.exception.ShardingSphereException; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.EnvironmentAware; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; import org.springframework.core.env.StandardEnvironment; import org.springframework.jndi.JndiObjectFactoryBean; import javax.naming.NamingException; import javax.sql.DataSource; import java.sql.SQLException; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * 自定义shardingsphere配置,实际拷贝自原配置文件,只做少量改动 * * @author lyc **/ @Configuration @ComponentScan({"org.apache.shardingsphere.spring.boot.converter"}) @EnableConfigurationProperties({SpringBootShardingRuleConfigurationProperties.class, SpringBootMasterSlaveRuleConfigurationProperties.class, SpringBootEncryptRuleConfigurationProperties.class, SpringBootPropertiesConfigurationProperties.class, SpringBootShadowRuleConfigurationProperties.class}) @ConditionalOnProperty( prefix = "spring.shardingsphere", name = {"enabled"}, havingValue = "true", matchIfMissing = true ) @AutoConfigureBefore({DruidDataSourceAutoConfigure.class, DataSourceAutoConfiguration.class}) public class MyShardingsphereConfig implements EnvironmentAware { private final SpringBootShardingRuleConfigurationProperties shardingRule; private final SpringBootMasterSlaveRuleConfigurationProperties masterSlaveRule; private final SpringBootEncryptRuleConfigurationProperties encryptRule; private final SpringBootShadowRuleConfigurationProperties shadowRule; private final SpringBootPropertiesConfigurationProperties props; private final Map<String, DataSource> dataSourceMap = new LinkedHashMap(); private static final String JNDI_NAME = "jndi-name"; private static final String DRUID_FILTER_PREFIX = "filters"; /** * 配置属性自动填充 * * @return */ @Bean @ConditionalOnMissingBean(SpringContextUtil.class) public SpringContextUtil springContextUtil() { return new SpringContextUtil(); } @Bean @Conditional({ShardingRuleCondition.class}) public DataSource shardingDataSource() throws SQLException { return ShardingDataSourceFactory.createDataSource(dataSourceMap, (new ShardingRuleConfigurationYamlSwapper()).swap(shardingRule), props.getProps()); } @Bean @Conditional({MasterSlaveRuleCondition.class}) public DataSource masterSlaveDataSource() throws SQLException { return MasterSlaveDataSourceFactory.createDataSource(dataSourceMap, (new MasterSlaveRuleConfigurationYamlSwapper()).swap(masterSlaveRule), props.getProps()); } @Bean @Conditional({EncryptRuleCondition.class}) public DataSource encryptDataSource() throws SQLException { return EncryptDataSourceFactory.createDataSource((DataSource) dataSourceMap.values().iterator().next(), (new EncryptRuleConfigurationYamlSwapper()).swap(encryptRule), props.getProps()); } @Bean @Conditional({ShadowRuleCondition.class}) public DataSource shadowDataSource() throws SQLException { return ShadowDataSourceFactory.createDataSource(dataSourceMap, (new ShadowRuleConfigurationYamlSwapper()).swap(shadowRule), props.getProps()); } @Bean public ShardingTransactionTypeScanner shardingTransactionTypeScanner() { return new ShardingTransactionTypeScanner(); } @Override public final void setEnvironment(Environment environment) { String prefix = "spring.shardingsphere.datasource."; for (String dsName : getDataSourceNames(environment, prefix)) { try { dataSourceMap.put(dsName, getDataSource(environment, prefix, dsName)); } catch (ReflectiveOperationException reflectiveOperationException) { throw new ShardingSphereException("Can't find datasource type!", reflectiveOperationException); } catch (NamingException namingException) { throw new ShardingSphereException("Can't find JNDI datasource!", namingException); } catch (SQLException sqlException) { throw new ShardingSphereException("set druidDatasource filters failed!", sqlException); } } } private List<String> getDataSourceNames(Environment environment, String prefix) { StandardEnvironment standardEnv = (StandardEnvironment) environment; standardEnv.setIgnoreUnresolvableNestedPlaceholders(true); return null == standardEnv.getProperty(prefix + "name") ? (new InlineExpressionParser(standardEnv.getProperty(prefix + "names"))).splitAndEvaluate() : Collections.singletonList(standardEnv.getProperty(prefix + "name")); } private DataSource getDataSource(Environment environment, String prefix, String dataSourceName) throws ReflectiveOperationException, NamingException, SQLException { Map<String, Object> dataSourceProps = (Map) PropertyUtil.handle(environment, prefix + dataSourceName.trim(), Map.class); Preconditions.checkState(!dataSourceProps.isEmpty(), "Wrong datasource properties!"); if (dataSourceProps.containsKey(JNDI_NAME)) { return getJndiDataSource(dataSourceProps.get(JNDI_NAME).toString()); } else { DataSource result = DataSourceUtil.getDataSource(dataSourceProps.get("type").toString(), dataSourceProps); //*******适配druidDataSource,添加filter,否则不能实现sql,防火墙等监控功能!!!************** if (result instanceof DruidDataSource) { if (dataSourceProps.get(DRUID_FILTER_PREFIX) != null) { ((DruidDataSource) result).setFilters(dataSourceProps.get(DRUID_FILTER_PREFIX).toString()); } } DataSourcePropertiesSetterHolder.getDataSourcePropertiesSetterByType(dataSourceProps.get("type").toString()).ifPresent((dataSourcePropertiesSetter) -> { dataSourcePropertiesSetter.propertiesSet(environment, prefix, dataSourceName, result); }); return result; } } private DataSource getJndiDataSource(String jndiName) throws NamingException { JndiObjectFactoryBean bean = new JndiObjectFactoryBean(); bean.setResourceRef(true); bean.setJndiName(jndiName); bean.setProxyInterface(DataSource.class); bean.afterPropertiesSet(); return (DataSource) bean.getObject(); } public MyShardingsphereConfig(SpringBootShardingRuleConfigurationProperties shardingRule, SpringBootMasterSlaveRuleConfigurationProperties masterSlaveRule, SpringBootEncryptRuleConfigurationProperties encryptRule, SpringBootShadowRuleConfigurationProperties shadowRule, SpringBootPropertiesConfigurationProperties props) { this.shardingRule = shardingRule; this.masterSlaveRule = masterSlaveRule; this.encryptRule = encryptRule; this.shadowRule = shadowRule; this.props = props; } } SpringBootApplication添加注解@SpringBootApplication(exclude = {SpringBootConfiguration.class, DataSourceAutoConfiguration.class}),不然也有坑