功能的注册与配置加载
以Governance分布式治理的注册中心为例
代码包整体是按照功能点划分,具体到每个功能,比如治理-代码大致分为spring-boot-starter启动加载相关;context上下文信息定义;core核心执行逻辑,比如对于注册中心,core包含了各类事件,监听的定义,等;api定义了基本的对外交互模型;对于注册中心,不同的实现又具有单独的repository-etcd类似结构目录,结构间的依赖关系源码已经定义好了
每个主要功能都有对应的启动加载类(sharding/shadow/readwrite/encrypt/db-discovery相同),注册中心起始于shardingsphere-jdbc-governance-spring-boot-starter
大体逻辑都是通过判断配置文件逻辑是否符合规范,符合则加载配置,创建对应的资源
1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package org.apache.shardingsphere.spring.boot.governance; 19 20 import com.google.common.base.Preconditions; 21 import lombok.RequiredArgsConstructor; 22 import org.apache.shardingsphere.driver.governance.internal.datasource.GovernanceShardingSphereDataSource; 23 import org.apache.shardingsphere.infra.config.RuleConfiguration; 24 import org.apache.shardingsphere.governance.core.yaml.config.swapper.RegistryCenterConfigurationYamlSwapper; 25 import org.apache.shardingsphere.governance.repository.api.config.GovernanceConfiguration; 26 import org.apache.shardingsphere.spring.boot.datasource.DataSourceMapSetter; 27 import org.apache.shardingsphere.spring.boot.governance.common.GovernanceSpringBootRootConfiguration; 28 import org.apache.shardingsphere.spring.boot.governance.rule.LocalRulesCondition; 29 import org.springframework.beans.factory.ObjectProvider; 30 import org.springframework.beans.factory.annotation.Autowired; 31 import org.springframework.boot.autoconfigure.AutoConfigureBefore; 32 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 33 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 34 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; 35 import org.springframework.boot.context.properties.EnableConfigurationProperties; 36 import org.springframework.context.EnvironmentAware; 37 import org.springframework.context.annotation.Bean; 38 import org.springframework.context.annotation.ComponentScan; 39 import org.springframework.context.annotation.Conditional; 40 import org.springframework.context.annotation.Configuration; 41 import org.springframework.core.env.Environment; 42 43 import javax.sql.DataSource; 44 import java.sql.SQLException; 45 import java.util.Collections; 46 import java.util.LinkedHashMap; 47 import java.util.List; 48 import java.util.Map; 49 import java.util.Objects; 50 import java.util.Optional; 51 52 /** 53 * Governance spring boot configuration. 54 */ 55 @Configuration 56 @ComponentScan("org.apache.shardingsphere.spring.boot.converter") 57 @EnableConfigurationProperties(GovernanceSpringBootRootConfiguration.class) 58 @ConditionalOnProperty(prefix = "spring.shardingsphere", name = "enabled", havingValue = "true", matchIfMissing = true) 59 @RequiredArgsConstructor 60 @AutoConfigureBefore(DataSourceAutoConfiguration.class) 61 public class ShardingSphereGovernanceAutoConfiguration implements EnvironmentAware { 62 63 private final Map<String, DataSource> dataSourceMap = new LinkedHashMap<>(); 64 65 private final GovernanceSpringBootRootConfiguration root; 66 67 private final RegistryCenterConfigurationYamlSwapper swapper = new RegistryCenterConfigurationYamlSwapper(); 68 69 /** 70 * Get governance configuration. 71 * 72 * @return governance configuration 73 */ 74 @Bean 75 public GovernanceConfiguration governanceConfiguration() { 76 Preconditions.checkState(Objects.nonNull(root.getGovernance()), "The governance configuration is invalid, please configure governance"); 77 return new GovernanceConfiguration(root.getGovernance().getName(), swapper.swapToObject(root.getGovernance().getRegistryCenter()), root.getGovernance().isOverwrite()); 78 } 79 80 /** 81 * Get governance ShardingSphere data source bean by local configuration. 82 * 83 * @param rules rules configuration 84 * @param governanceConfig governance configuration 85 * @return governance sharding data source bean 86 * @throws SQLException SQL exception 87 */ 88 @Bean 89 @Conditional(LocalRulesCondition.class) 90 @Autowired(required = false) 91 public DataSource localShardingSphereDataSource(final ObjectProvider<List<RuleConfiguration>> rules, final GovernanceConfiguration governanceConfig) throws SQLException { 92 List<RuleConfiguration> ruleConfigurations = Optional.ofNullable(rules.getIfAvailable()).orElse(Collections.emptyList()); 93 return createDataSourceWithRules(ruleConfigurations, governanceConfig); 94 } 95 96 /** 97 * Get data source bean from registry center. 98 * 99 * @param governanceConfig governance configuration 100 * @return data source bean 101 * @throws SQLException SQL Exception 102 */ 103 @Bean 104 @ConditionalOnMissingBean(DataSource.class) 105 public DataSource dataSource(final GovernanceConfiguration governanceConfig) throws SQLException { 106 return createDataSourceWithoutRules(governanceConfig); 107 } 108 109 @Override 110 public final void setEnvironment(final Environment environment) { 111 dataSourceMap.putAll(DataSourceMapSetter.getDataSourceMap(environment)); 112 } 113 114 private DataSource createDataSourceWithRules(final List<RuleConfiguration> ruleConfigs, final GovernanceConfiguration governanceConfig) throws SQLException { 115 return new GovernanceShardingSphereDataSource(dataSourceMap, ruleConfigs, root.getProps(), governanceConfig); 116 } 117 118 private DataSource createDataSourceWithoutRules(final GovernanceConfiguration governanceConfig) throws SQLException { 119 return new GovernanceShardingSphereDataSource(governanceConfig); 120 } 121 }
如果是加了@***Condition的,会做逻辑配置逻辑检查
public final class ReadwriteSplittingSpringBootCondition extends SpringBootCondition { private static final String PREFIX = "spring.shardingsphere.rules.readwrite-splitting"; @Override public ConditionOutcome getMatchOutcome(final ConditionContext conditionContext, final AnnotatedTypeMetadata annotatedTypeMetadata) { return PropertyUtil.containPropertyPrefix(conditionContext.getEnvironment(), PREFIX) ? ConditionOutcome.match() : ConditionOutcome.noMatch("Can't find ShardingSphere readwrite-splitting rule configuration in local file."); } }
通过反射判断
@SneakyThrows(ReflectiveOperationException.class) private static Object v2(final Environment environment, final String prefix, final Class<?> targetClass) { Class<?> binderClass = Class.forName("org.springframework.boot.context.properties.bind.Binder"); Method getMethod = binderClass.getDeclaredMethod("get", Environment.class); Method bindMethod = binderClass.getDeclaredMethod("bind", String.class, Class.class); Object binderObject = getMethod.invoke(null, environment); String prefixParam = prefix.endsWith(".") ? prefix.substring(0, prefix.length() - 1) : prefix; Object bindResultObject = bindMethod.invoke(binderObject, prefixParam, targetClass); Method resultGetMethod = bindResultObject.getClass().getDeclaredMethod("get"); return resultGetMethod.invoke(bindResultObject); }
最终通过按照转换后的配置对象构建对应的服务资源对象
--------------------------------------------------------------------------
注册中心目前支持zookeeper/etcd
服务加载方式全部是基于ServiceLoader,有些是默认在源码包里加载的,比如org.apache.shardingsphere.governance.repository.zookeeper.CuratorZookeeperRepository就通过下图文件启动,也有些可以自己实现然后添加的
加载方式
@NoArgsConstructor(access = AccessLevel.PRIVATE) public final class RegistryCenterRepositoryFactory { static { ShardingSphereServiceLoader.register(RegistryCenterRepository.class); } /** * Create new instance of Registry center repository. * * @param config governance configuration * @return new instance of Registry center repository */ public static RegistryCenterRepository newInstance(final GovernanceConfiguration config) { RegistryCenterConfiguration registryCenterConfig = config.getRegistryCenterConfiguration(); Preconditions.checkNotNull(registryCenterConfig, "Registry center configuration cannot be null."); RegistryCenterRepository result = TypedSPIRegistry.getRegisteredService(RegistryCenterRepository.class, registryCenterConfig.getType(), registryCenterConfig.getProps()); result.init(config.getName(), registryCenterConfig); return result; } }
注册中心需要实现的逻辑也很简单,看图就知道了
整个注册中心基于临时节点跟session生命周期相同的特性实现实例和数据库的注册发现,基于监听机制实现配置变更的发现通知
通过google eventbus事件机制传递到观察者实现配置动态化
zk治理节点