1.Java版Provider启动内容
public class Provider {
public static void main(String[] args) throws IOException {
// 服务实现
DemoService demoService = new DemoServiceImpl();
// 当前应用配置
ApplicationConfig application = new ApplicationConfig();
application.setName("hello-world-app-provider");
// 连接注册中心配置
RegistryConfig registry = new RegistryConfig();
registry.setAddress("zookeeper://192.168.133.129:2181");
// 服务提供者协议配置
ProtocolConfig protocol = new ProtocolConfig();
protocol.setName("dubbo");
protocol.setPort(20880);
//protocol.setThreads(200);
// 注意:ServiceConfig为重对象,内部封装了与注册中心的连接,以及开启服务端口
// 服务提供者暴露服务配置
ServiceConfig<DemoService> service = new ServiceConfig<DemoService>(); // 此实例很重,封装了与注册中心的连接,请自行缓存,否则可能造成内存和连接泄漏
service.setApplication(application);
service.setRegistry(registry); // 多个注册中心可以用setRegistries()
service.setProtocol(protocol); // 多个协议可以用setProtocols()
service.setInterface(DemoService.class);
service.setRef(demoService);
service.setVersion("1.0.0");
// 暴露及注册服务
service.export();
System.in.read(); //需要等待
}
}
2.ApplicationConfig的源码查看
public ApplicationConfig() {
}
public void setName(String name) {
checkName(NAME, name);//检查程序的名称
this.name = name;
if (StringUtils.isEmpty(id)) {
id = name;
}
}
发现当前的setName就是设置当前程序的名称,没有特殊的操作
3.查看RegistryConfig的源码
//当前RegistryConfig的构造函数
public RegistryConfig() {
}
//当前调用的setAddress
public void setAddress(String address) {
this.address = address;
if (address != null) {//当前的address肯定不为null
int i = address.indexOf("://");//获取"://"所在的位置
if (i > 0) {
this.updateIdIfAbsent(address.substring(0, i));//这里实际上调用的是AbstractConfig中的方法
}
}
}
//当前父类AbstractConfig类中的updateIdIfAbsent方法
public void updateIdIfAbsent(String value) {
if (StringUtils.isNotEmpty(value) && StringUtils.isEmpty(id)) {
this.id = value;//显示zookeeper
}
}
通过debug发现当前的setAddress中就是设置address,而updateIdIfAbsent是用来设置当前父辈的id为zookeeper
当前的RegistryConfig也没有什么特殊的
4.查看ProtocolConfig源码
public ProtocolConfig() {
}
public final void setName(String name) {
checkName("name", name);
this.name = name;
this.updateIdIfAbsent(name);//实际上还是调用AbstractConfig中的updateIdIfAbsent方法
}
public final void setPort(Integer port) {
this.port = port;
}
通过查看源码发现当前的ProtocolConfig就是用来设置端口和协议名称的类,没有特殊的方法
5.查看ServiceConfig源码(dubbo连接zookeeper的方式)
5.1 查看set方法和构造方法
//构造方法
public ServiceConfig() {
}
//set等方法
public void setApplication(ApplicationConfig application) {
ConfigManager.getInstance().setApplication(application);//通过当前的ConfigManager源码发现这个是一个懒汉的单例模式,这个类中具有基本上所有的配置信息
this.application = application;
}
//setRegistry方法
public void setRegistry(RegistryConfig registry) {
List<RegistryConfig> registries = new ArrayList<RegistryConfig>(1);
registries.add(registry);
setRegistries(registries);
}
//查看setRegistries方法
@SuppressWarnings({"unchecked"})
public void setRegistries(List<? extends RegistryConfig> registries) {
ConfigManager.getInstance().addRegistries((List<RegistryConfig>) registries);//发现还是调用ConfigManager单例类中的addRegistries方法
this.registries = (List<RegistryConfig>) registries;//设置当前的ServiceConfig中设置registries
}
//setProtocol方法
public void setProtocol(ProtocolConfig protocol) {
setProtocols(new ArrayList<>(Arrays.asList(protocol)));
}
@SuppressWarnings({"unchecked"})
public void setProtocols(List<? extends ProtocolConfig> protocols) {
ConfigManager.getInstance().addProtocols((List<ProtocolConfig>) protocols);//发现调用了ConfigManager中添加Protocols
this.protocols = (List<ProtocolConfig>) protocols;//设置当前ServiceConfig类的协议
}
//setInterface方法
public void setInterface(Class<?> interfaceClass) {
//判断当前色通知的接口类是否为null和当前的类是否为接口类,如果不满足则抛出异常
if (interfaceClass != null && !interfaceClass.isInterface()) {
throw new IllegalStateException("The interface class " + interfaceClass + " is not a interface!");
}
this.interfaceClass = interfaceClass;
setInterface(interfaceClass == null ? null : interfaceClass.getName());
}
public void setInterface(String interfaceName) {
this.interfaceName = interfaceName;//设置当前的接口名
if (StringUtils.isEmpty(id)) {
id = interfaceName;
}
}
//setRef方法
public void setRef(T ref) {
this.ref = ref;
}
//setVersion方法
public void setVersion(String version) {
checkKey(VERSION_KEY, version);//检查版本
this.version = version;
}
通过源码发现当前的set方法与ConfigManager这个单例类关系密切,当前的ConfigManager这个类中具有当前添加的属性
5.2 查看ServiceConfig中的export方法
public synchronized void export() {
checkAndUpdateSubConfigs();//通过debug发现当前的这个方法是最重要的方法
if (!shouldExport()) {//是否应该暴露,false表示结束函数
return;
}
if (shouldDelay()) {//判断当前是否有日程
DELAY_EXPORT_EXECUTOR.schedule(this::doExport, getDelay(), TimeUnit.MILLISECONDS);
} else {
doExport();//通过debug发现当前调用了doExprot方法而doExport方法调用了 doExportUrls()方法
}
}
1.通过debug发现实际上调用的是checkAndUpdateSubConfigs方法,才会再控制台打印一大堆输出,并连接到了当前的zookeeper中
2.通过debug发现当前的doExport方法是在连接到zookeeper后才会执行的方法,这个方法会调用doExportUrls方法暴露访问的url
5.3 查看ServiceConfig中的checkAndUpdateSubConfigs方法
public void checkAndUpdateSubConfigs() {
// 使用在全局配置上显式定义的默认配置
completeCompoundConfigs();
// Config Center should always being started first.
//首先启动配置中心
startConfigCenter();
//检查默认配置
checkDefault();
//然后检查协议
checkProtocol();
//检查程序
checkApplication();
// if protocol is not injvm checkRegistry
//如果当前的协议不是injvm就开始检查注册
if (!isOnlyInJvm()) {
checkRegistry();//通过debug发现当前的方法进入这里后就不执行了,说明这里才是核心方法
}
this.refresh();//刷新
checkMetadataReport();//检查mate数据的报道
if (StringUtils.isEmpty(interfaceName)) {//再次判断接口是否为空空
throw new IllegalStateException("<dubbo:service interface=\"\" /> interface not allow null!");
}
//如果当前的接口是GenericService,则进行处理
if (ref instanceof GenericService) {
interfaceClass = GenericService.class;
if (StringUtils.isEmpty(generic)) {
generic = Boolean.TRUE.toString();
}
} else {
try {
//否者尝试通过当前线程类的类加载方式加载接口类
interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
.getContextClassLoader());
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e.getMessage(), e);
}
//然后检查接口和接口中的方法
checkInterfaceAndMethods(interfaceClass, methods);
//检查当前接口提供的实现类
checkRef();
generic = Boolean.FALSE.toString();
}
if (local != null) {
if ("true".equals(local)) {
local = interfaceName + "Local";
}
Class<?> localClass;
try {
localClass = ClassUtils.forNameWithThreadContextClassLoader(local);
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e.getMessage(), e);
}
if (!interfaceClass.isAssignableFrom(localClass)) {
throw new IllegalStateException("The local implementation class " + localClass.getName() + " not implement interface " + interfaceName);
}
}
if (stub != null) {
if ("true".equals(stub)) {
stub = interfaceName + "Stub";
}
Class<?> stubClass;
try {
//加载子类
stubClass = ClassUtils.forNameWithThreadContextClassLoader(stub);
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e.getMessage(), e);
}
if (!interfaceClass.isAssignableFrom(stubClass)) {
throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + interfaceName);
}
}
//检查子类和Local
checkStubAndLocal(interfaceClass);
checkMock(interfaceClass);
}
通过当前的方法发现checkRegistry()这个方法才是连接Zookeeper的返回
5.4 查看ServiceConfig中的checkRegistry方法
protected void checkRegistry() {
loadRegistriesFromBackwardConfig();//通过配置加载当前注册中心
convertRegistryIdsToRegistries();//转换注册到注册中心
for (RegistryConfig registryConfig : registries) {
if (!registryConfig.isValid()) {
throw new IllegalStateException("No registry config found or it's not a valid config! " +
"The registry config is: " + registryConfig);
}
}
useRegistryForConfigIfNecessary();//使用注册配置,通过debug发现这里才是重点
}
通过debug发现当前的useRegistryForConfigIfNecessary方法才是重点
5.5 查看AbstractInterfaceConfig中的useRegistryForConfigIfNecessary方法
private void useRegistryForConfigIfNecessary() {
registries.stream().filter(RegistryConfig::isZookeeperProtocol).findFirst().ifPresent(rc -> {
// we use the loading status of DynamicConfiguration to decide whether ConfigCenter has been initiated.
Environment.getInstance().getDynamicConfiguration().orElseGet(() -> {
//获取配置管理器
ConfigManager configManager = ConfigManager.getInstance();
ConfigCenterConfig cc = configManager.getConfigCenter().orElse(new ConfigCenterConfig());
cc.setProtocol(rc.getProtocol());//创建配置中心的配置
cc.setAddress(rc.getAddress());
cc.setHighestPriority(false);
setConfigCenter(cc);
startConfigCenter();//这里是启动配置中心
return null;
});
});
}
这里的启动配置中心才是启动连接的关键startConfigCenter
5.6 查看AbstractInterfaceConfig中的startConfigCenter方法
void startConfigCenter() {
if (configCenter == null) {//用于检查配置中心是否初始化
ConfigManager.getInstance().getConfigCenter().ifPresent(cc -> this.configCenter = cc);//初始化配置中心
}
if (this.configCenter != null) {//这里肯定不为null
// TODO there may have duplicate refresh
this.configCenter.refresh();//刷新当前的配置中心
prepareEnvironment();//准备环境
}
ConfigManager.getInstance().refreshAll();//通过配置管理刷新所有的数据
}
debug发现当前的prepareEnvironment方法为重要方法
5.7 查看AbstractInterfaceConfig的prepareEnvironment方法
private void prepareEnvironment() {
if (configCenter.isValid()) {//校验当前的配置中心
if (!configCenter.checkOrUpdateInited()) {//如果配置中心为初始化就停止函数
return;
}
DynamicConfiguration dynamicConfiguration = getDynamicConfiguration(configCenter.toUrl());//通过这里发现dynamicConfiguration 的实例为:ZookeeperDynamicConfiguration
String configContent = dynamicConfiguration.getProperties(configCenter.getConfigFile(), configCenter.getGroup());
String appGroup = application != null ? application.getName() : null;
String appConfigContent = null;
if (StringUtils.isNotEmpty(appGroup)) {
appConfigContent = dynamicConfiguration.getProperties
(StringUtils.isNotEmpty(configCenter.getAppConfigFile()) ? configCenter.getAppConfigFile() : configCenter.getConfigFile(),
appGroup
);
}
try {
Environment.getInstance().setConfigCenterFirst(configCenter.isHighestPriority());
Environment.getInstance().updateExternalConfigurationMap(parseProperties(configContent));
Environment.getInstance().updateAppExternalConfigurationMap(parseProperties(appConfigContent));
} catch (IOException e) {
throw new IllegalStateException("Failed to parse configurations from Config Center.", e);
}
}
}
5.8 ZookeeperDynamicConfiguration这个类的的构造函数
ZookeeperDynamicConfiguration(URL url, ZookeeperTransporter zookeeperTransporter) {
this.url = url;
rootPath = PATH_SEPARATOR + url.getParameter(CONFIG_NAMESPACE_KEY, DEFAULT_GROUP) + "/config";
initializedLatch = new CountDownLatch(1);
this.cacheListener = new CacheListener(rootPath, initializedLatch);
this.executor = Executors.newFixedThreadPool(1, new NamedThreadFactory(this.getClass().getSimpleName(), true));
zkClient = zookeeperTransporter.connect(url);//发现这里有一个connect方法,这个就是连接Zookeeper的主要方法
zkClient.addDataListener(rootPath, cacheListener, executor);//然后为当前的zookeeper客户端添加数据监听
try {
// Wait for connection
this.initializedLatch.await();//等待连接
} catch (InterruptedException e) {
logger.warn("Failed to build local cache for config center (zookeeper)." + url);
}
}
1.通过ZookeeperDynamicConfiguration发现当前的这个类被实例化的时候会连接注册中心,并且还有添加数据监听!
2.然后会回到 5.6中的ConfigManager.getInstance().refreshAll();刷新所有的配置信息
3.然后回到ServiceConfig这个类的checkAndUpdateSubConfigs方法中的interfaceClass = Class.forName()创建接口类,然后检查当前接口的实例类,完成当前的配置信息的更新
6.查看ServiceConfig的doExport方法(暴露服务让外界调用)
protected synchronized void doExport() {
if (unexported) {
throw new IllegalStateException("The service " + interfaceClass.getName() + " has already unexported!");
}
if (exported) {
return;
}
exported = true;
if (StringUtils.isEmpty(path)) {
path = interfaceName;
}
doExportUrls();//实际调用doExportUrls()
}
6.1 查看ServiceConfig的doExportUrls方法
@SuppressWarnings({"unchecked", "rawtypes"})
private void doExportUrls() {
List<URL> registryURLs = loadRegistries(true);//获取组测中心的路劲
for (ProtocolConfig protocolConfig : protocols) {
//获取访问的路径的key
String pathKey = URL.buildKey(getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), group, version);
//通过当前的接口类和实现类创建服务提供者模型
ProviderModel providerModel = new ProviderModel(pathKey, ref, interfaceClass);
ApplicationModel.initProviderModel(pathKey, providerModel);
doExportUrlsFor1Protocol(protocolConfig, registryURLs);//这里是通过当前的协议暴露可以访问的urls
}
}
通过源码发现暴露服务其实是通过doExportUrlsFor1Protocol实现的
6.2 查看ServiceConfig的doExportUrlsFor1Protocol方法
private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
String name = protocolConfig.getName();//获取协议的名称
if (StringUtils.isEmpty(name)) {//如果名称为null则设置协议名称为dubbo
name = DUBBO;
}
Map<String, String> map = new HashMap<String, String>();
map.put(SIDE_KEY, PROVIDER_SIDE);
appendRuntimeParameters(map);
appendParameters(map, metrics);
appendParameters(map, application);
appendParameters(map, module);
// remove 'default.' prefix for configs from ProviderConfig
// appendParameters(map, provider, Constants.DEFAULT_KEY);
appendParameters(map, provider);
appendParameters(map, protocolConfig);
appendParameters(map, this);
//通过集合工具半段当前的方法不是空的
//协议检查,添加方法或者其他的版本信息
if (ProtocolUtils.isGeneric(generic)) {
map.put(GENERIC_KEY, generic);
map.put(METHODS_KEY, ANY_VALUE);
} else {
String revision = Version.getVersion(interfaceClass, version);
if (revision != null && revision.length() > 0) {
map.put(REVISION_KEY, revision);
}
String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();//获取当前接口中的所有的方法的名称
if (methods.length == 0) {
logger.warn("No method found in service interface " + interfaceClass.getName());
map.put(METHODS_KEY, ANY_VALUE);
} else {
map.put(METHODS_KEY, StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ","));//向当前的map集合中添加当前被映射的方法名称
}
}
if (!ConfigUtils.isEmpty(token)) {
if (ConfigUtils.isDefault(token)) {
map.put(TOKEN_KEY, UUID.randomUUID().toString());
} else {
map.put(TOKEN_KEY, token);
}
}
// export service,开始暴露服务
String host = this.findConfigedHosts(protocolConfig, registryURLs, map);//获取当前配置的host地址
//获取访问的端口
Integer port = this.findConfigedPorts(protocolConfig, name, map);
//创建可访问的url
URL url = new URL(name, host, port, getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), map);
if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
.hasExtension(url.getProtocol())) {
url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
.getExtension(url.getProtocol()).getConfigurator(url).configure(url);
}
String scope = url.getParameter(SCOPE_KEY);
// don't export when none is configured
if (!SCOPE_NONE.equalsIgnoreCase(scope)) {
// export to local if the config is not remote (export to remote only when config is remote)
if (!SCOPE_REMOTE.equalsIgnoreCase(scope)) {
exportLocal(url);
}
// export to remote if the config is not local (export to local only when config is local)
if (!SCOPE_LOCAL.equalsIgnoreCase(scope)) {
if (!isOnlyInJvm() && logger.isInfoEnabled()) {
logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
}
if (CollectionUtils.isNotEmpty(registryURLs)) {
for (URL registryURL : registryURLs) {
//if protocol is only injvm ,not register
if (LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
continue;
}
url = url.addParameterIfAbsent(DYNAMIC_KEY, registryURL.getParameter(DYNAMIC_KEY));
URL monitorUrl = loadMonitor(registryURL);
if (monitorUrl != null) {
url = url.addParameterAndEncoded(MONITOR_KEY, monitorUrl.toFullString());
}
if (logger.isInfoEnabled()) {
logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL);
}
// For providers, this is used to enable custom proxy to generate invoker
String proxy = url.getParameter(PROXY_KEY);
if (StringUtils.isNotEmpty(proxy)) {
registryURL = registryURL.addParameter(PROXY_KEY, proxy);
}
Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString()));
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
Exporter<?> exporter = protocol.export(wrapperInvoker);
exporters.add(exporter);
}
} else {
Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, url);
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
Exporter<?> exporter = protocol.export(wrapperInvoker);
exporters.add(exporter);
}
/**
* @since 2.7.0
* ServiceData Store
*/
MetadataReportService metadataReportService = null;
if ((metadataReportService = getMetadataReportService()) != null) {
metadataReportService.publishProvider(url);
}
}
}
this.urls.add(url);
}
通过这个方法发现其实dubbo就是通过发布一个基于dubbo协议的url,通过一个可访问的url的方式调用当前的对应接口实现类的方法达到效果
7.总结
1.dubbo需要连接zookeeper注册中心
2.dubbo创建当前发布的接口中的方法名来创建自己的基于dubbo协议的url
3.dubbo开始发布这个可以访问的url
,即通过这个url就能访问对应的接口实现类的的方法