(1). Sharding-JDBC 源码该如何跟踪?
通过:sharding-jdbc-spring-boot-starter-4.1.1.jar/META-INF/spring.factories找到Spring Boot的入口.
(2). application.properties
server.port=8080
spring.application.name=sharding-jdbc-demo
spring.http.encoding.enabled=true
spring.http.encoding.charset=UTF-8
spring.http.encoding.force=true
spring.main.allow-bean-definition-overriding=true
# mybatis配置
mybatis.configuration.map-underscore-to-camel-case=true
# 日志配置信息
logging.level.root=info
logging.level.org.springframework.web=info
logging.level.com.itheima.dbsharding =debug
logging.level.druid.sql=debug
#配置数据源的名称(多个之间用逗号分隔).
spring.shardingsphere.datasource.names=d1,d2
# 水平分库案例,在d1和d2表结构都一样.
# 数据源名称:d1对应的详细信息
spring.shardingsphere.datasource.d1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.d1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.d1.url=jdbc:mysql://localhost:3306/order_db?useUnicode=true
spring.shardingsphere.datasource.d1.username=root
spring.shardingsphere.datasource.d1.password=123456
# 数据源名称:d2对应的详细信息
spring.shardingsphere.datasource.d2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.d2.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.d2.url=jdbc:mysql://localhost:3307/order_db?useUnicode=true
spring.shardingsphere.datasource.d2.username=root
spring.shardingsphere.datasource.d2.password=123456
############################################逻辑表配置项开始####################################################
# org.apache.shardingsphere.shardingjdbc.spring.boot.sharding.SpringBootShardingRuleConfigurationProperties
# org.apache.shardingsphere.core.yaml.config.sharding.YamlShardingRuleConfiguration
# 指定逻辑表:t_order的数据节点:[d1/d2].t_order_1,d1.t_order_2
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=d$->{1..2}.t_order_$->{1..2}
# 分库实际要做的是找到对应上面的数据源名称
spring.shardingsphere.sharding.tables.t_order.database-strategy.inline.sharding-column=user_id
spring.shardingsphere.sharding.tables.t_order.database-strategy.inline.algorithm-expression=d$->{user_id % 2 + 1}
# 指定逻辑表t_order表的主键(order_id)生成策略为:雪花算法.
# org.apache.shardingsphere.core.yaml.config.sharding.YamlKeyGeneratorConfiguration
spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id
spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE
# 分表实际要做的找到真实的表名称(t_order_1/t_order_2)
# 指定t_order表的分片策略,分片策略包括分片键和分片算法
# org.apache.shardingsphere.core.yaml.config.sharding.YamlShardingStrategyConfiguration
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column=order_id
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression=t_order_$->{order_id % 2 + 1}
############################################逻辑表配置项结束####################################################
# 打开sharding-jdbc的日志.
spring.shardingsphere.props.sql.show=true
(3). SpringBootConfiguration.shardingDataSource
- 初始化真实的DataSource.
- 创建事务AOP.
- 通过ShardingDataSourceFactory(典型工厂模式)工厂类,创建:ShardingDataSource,代理多个:DataSource.
package org.apache.shardingsphere.shardingjdbc.spring.boot;
@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(DataSourceAutoConfiguration.class)
@RequiredArgsConstructor
public class SpringBootConfiguration
// **********************************************************
// 2. 由于实现了:EnvironmentAware,所以Spring会回调该方法
// **********************************************************
implements EnvironmentAware {
// **********************************************************
// 1. 由于@EnableConfigurationProperties({})
// Spring会读取配置文件,并映射到实体模型上.
// **********************************************************
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 final String jndiName = "jndi-name";
// ***************************************************************
// 3. 创建事务扫描器(@ShardingTransactionType)
// ***************************************************************
@Bean
public ShardingTransactionTypeScanner shardingTransactionTypeScanner() {
return new ShardingTransactionTypeScanner();
}
// ***************************************************************
// 4. 基于前面创建的DataSource,封装成一个新的:DataSource,即:ShardingDataSource类
// ***************************************************************
@Bean
@Conditional(ShardingRuleCondition.class)
public DataSource shardingDataSource() throws SQLException {
return ShardingDataSourceFactory.createDataSource(dataSourceMap, new ShardingRuleConfigurationYamlSwapper().swap(shardingRule), props.getProps());
}
// **********************************************************
// 2. 由于实现了:EnvironmentAware,所以Spring会回调该方法
// **********************************************************
public final void setEnvironment(final Environment environment) {
String prefix = "spring.shardingsphere.datasource.";
// 2.1 getDataSourceNames
for (String each : getDataSourceNames(environment, prefix)) {
try {
// 2.3 getDataSource
// 初始化数据源,通过:SpringBootConfiguration.dataSourceMap
// Hold住所有用户定义的数据源.
dataSourceMap.put(each, getDataSource(environment, prefix, each));
} catch (final ReflectiveOperationException ex) {
throw new ShardingSphereException("Can't find datasource type!", ex);
} catch (final NamingException namingEx) {
throw new ShardingSphereException("Can't find JNDI datasource!", namingEx);
}
}
}// end setEnvironment
// 2.2 getDataSourceNames
private List<String> getDataSourceNames(final Environment environment, final String prefix) {
StandardEnvironment standardEnv = (StandardEnvironment) environment;
standardEnv.setIgnoreUnresolvableNestedPlaceholders(true);
// spring.shardingsphere.datasource.name
// spring.shardingsphere.datasource.names
return null == standardEnv.getProperty(prefix + "name")
? new InlineExpressionParser(standardEnv.getProperty(prefix + "names")).splitAndEvaluate() : Collections.singletonList(standardEnv.getProperty(prefix + "name"));
} // end getDataSourceNames
// 2.3 getDataSource
private DataSource getDataSource(final Environment environment, final String prefix, final String dataSourceName) throws ReflectiveOperationException, NamingException {
Map<String, Object> dataSourceProps = PropertyUtil.handle(environment, prefix + dataSourceName.trim(), Map.class);
Preconditions.checkState(!dataSourceProps.isEmpty(), "Wrong datasource properties!");
if (dataSourceProps.containsKey(jndiName)) {
return getJndiDataSource(dataSourceProps.get(jndiName).toString());
}
DataSource result = DataSourceUtil.getDataSource(dataSourceProps.get("type").toString(), dataSourceProps);
DataSourcePropertiesSetterHolder.getDataSourcePropertiesSetterByType(dataSourceProps.get("type").toString()).ifPresent(
dataSourcePropertiesSetter -> dataSourcePropertiesSetter.propertiesSet(environment, prefix, dataSourceName, result));
return result;
} // end getDataSource
}
(4). 总结
Sharding-JDBC对DataSource(ShardingDataSource)进行了扩展,应用程序获取Connection时,将会是调用:ShardingDataSource.getConnection方法.
所以:Sharding-JDBC代码的入口是:ShardingDataSource类.