nacos服务注册源码过程阅读
创始人
2024-02-10 15:13:23

准备部分

在这里插入图片描述

这是在真正调用注册实例的方法之前,需要使用到的对象的关系图。

源码跟踪

NacosServiceRegistryAutoConfiguration类

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
@ConditionalOnNacosDiscoveryEnabled
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",matchIfMissing = true)
@AutoConfigureAfter({ AutoServiceRegistrationConfiguration.class,AutoServiceRegistrationAutoConfiguration.class,NacosDiscoveryAutoConfiguration.class })
public class NacosServiceRegistryAutoConfiguration {@Beanpublic NacosServiceRegistry nacosServiceRegistry(//  在spring.factories中,有个自动创建的类是 NacosServiceAutoConfiguration,这个类里创建了 NacosServiceManager 对象,也就是对应这里的第一个参数NacosServiceManager nacosServiceManager, NacosDiscoveryProperties nacosDiscoveryProperties) {   //  取的配置文件return new NacosServiceRegistry(nacosServiceManager, nacosDiscoveryProperties);}@Bean@ConditionalOnBean(AutoServiceRegistrationProperties.class)public NacosRegistration nacosRegistration(ObjectProvider> registrationCustomizers,  // 不知道是个啥,感觉不是重点所以没看NacosDiscoveryProperties nacosDiscoveryProperties,  // 配置文件ApplicationContext context) {   // spring容器创建的return new NacosRegistration(registrationCustomizers.getIfAvailable(),nacosDiscoveryProperties, context);}@Bean@ConditionalOnBean(AutoServiceRegistrationProperties.class)这个是才是重点对象public NacosAutoServiceRegistration nacosAutoServiceRegistration(NacosServiceRegistry registry,  // 上面第一个方法创建的BeanAutoServiceRegistrationProperties autoServiceRegistrationProperties,    // 取的配置文件中的值NacosRegistration registration) {  // 上面第二个方法创建的Beanreturn new NacosAutoServiceRegistration(registry,autoServiceRegistrationProperties, registration);}}

AbstractAutoServiceRegistration类

直接看NacosAutoServiceRegistration继承的这个抽象类

	@Override@SuppressWarnings("deprecation")//  NacosAutoServiceRegistration类有实现ApplicationListener,所以会监听到WebServerInitializedEvent事件public void onApplicationEvent(WebServerInitializedEvent event) {bind(event);}public void bind(WebServerInitializedEvent event) {ApplicationContext context = event.getApplicationContext();if (context instanceof ConfigurableWebServerApplicationContext) {if ("management".equals(((ConfigurableWebServerApplicationContext) context).getServerNamespace())) {return;}}this.port.compareAndSet(0, event.getWebServer().getPort());this.start();}public void start() {if (!isEnabled()) {if (logger.isDebugEnabled()) {logger.debug("Discovery Lifecycle disabled. Not starting");}return;}if (!this.running.get()) {//  NacosServiceManager类中的 onInstancePreRegisteredEvent 方法上有@EventListener,会监听到这个预注册事件,具体不知道逻辑,看变量名称好像缓存		    	                  用的this.context.publishEvent(new InstancePreRegisteredEvent(this, getRegistration()));// 会调用register方法register();if (shouldRegisterManagement()) {registerManagement();}this.context.publishEvent(new InstanceRegisteredEvent<>(this, getConfiguration()));this.running.compareAndSet(false, true);}}

NacosServiceRegistry类

一直溯源register方法,会看到NacosServiceRegistry类中的register(Registration registration)方法,

@Overridepublic void register(Registration registration) {if (StringUtils.isEmpty(registration.getServiceId())) {log.warn("No service to register for nacos client...");return;}//  这里的namingService()溯源会看到创建这个NamingService 用到了反射NamingService namingService = namingService();// serviceId 其实就是spring.application.name值String serviceId = registration.getServiceId();String group = nacosDiscoveryProperties.getGroup();// 直接new一个Instance对象Instance instance = getNacosInstanceFromRegistration(registration);try {namingService.registerInstance(serviceId, group, instance);log.info("nacos registry, {} {} {}:{} register finished", group, serviceId,instance.getIp(), instance.getPort());}catch (Exception e) {if (nacosDiscoveryProperties.isFailFast()) {log.error("nacos registry, {} register failed...{},", serviceId,registration.toString(), e);rethrowRuntimeException(e);}else {log.warn("Failfast is false. {} register failed...{},", serviceId,registration.toString(), e);}}}

创建NamingService的具体代码:

    public static NamingService createNamingService(Properties properties) throws NacosException {try {Class driverImplClass = Class.forName("com.alibaba.nacos.client.naming.NacosNamingService");Constructor constructor = driverImplClass.getConstructor(Properties.class);NamingService vendorImpl = (NamingService)constructor.newInstance(properties);return vendorImpl;} catch (Throwable var4) {throw new NacosException(-400, var4);}}

NacosNamingService类

    public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {//  这里校验的就是配置的心跳间隔和心跳超时,ip删除超时三个参数的值的大小关系,心跳间隔必须比这两个都要小NamingUtils.checkInstanceIsLegal(instance);String groupedServiceName = NamingUtils.getGroupedName(serviceName, groupName);//  如果是临时实例,就会开一个心跳线程,不设置事件默认应该是5s的延迟if (instance.isEphemeral()) {BeatInfo beatInfo = this.beatReactor.buildBeatInfo(groupedServiceName, instance);this.beatReactor.addBeatInfo(groupedServiceName, beatInfo);}this.serverProxy.registerService(groupedServiceName, groupName, instance);}

NamingProxy类

    public String callServer(String api, Map params, Map body, String curServer, String method) throws NacosException {long start = System.currentTimeMillis();long end = 0L;this.injectSecurityInfo(params);Header header = this.builderHeader();String url;if (!curServer.startsWith("https://") && !curServer.startsWith("http://")) {if (!IPUtil.containsPort(curServer)) {curServer = curServer + ":" + this.serverPort;}url = NamingHttpClientManager.getInstance().getPrefix() + curServer + api;} else {url = curServer + api;}try {// 这里的nacosRestTemplate 点进去溯源之后会发现 HttpRestResult restResult = this.nacosRestTemplate.exchangeForm(url, header, Query.newInstance().initParams(params), body, method, String.class);end = System.currentTimeMillis();MetricsMonitor.getNamingRequestMonitor(method, url, String.valueOf(restResult.getCode())).observe((double)(end - start));if (restResult.ok()) {return (String)restResult.getData();} else if (304 == restResult.getCode()) {return "";} else {throw new NacosException(restResult.getCode(), restResult.getMessage());}} catch (Exception var13) {LogUtils.NAMING_LOGGER.error("[NA] failed to request", var13);throw new NacosException(500, var13);}}
// 先是在NamingProxy中显式创建NacosRestTemplate 对象
private final NacosRestTemplate nacosRestTemplate = NamingHttpClientManager.getInstance().getNacosRestTemplate();NamingHttpClientManager类//  这里传入的参数其实是NamingHttpClientFactory对象,并且这个对象是继承了AbstractHttpClientFactory抽象类的public NacosRestTemplate getNacosRestTemplate() {return HttpClientBeanHolder.getNacosRestTemplate(HTTP_CLIENT_FACTORY);}HttpClientBeanHolder类public static NacosRestTemplate getNacosRestTemplate(HttpClientFactory httpClientFactory) {if (httpClientFactory == null) {throw new NullPointerException("httpClientFactory is null");}String factoryName = httpClientFactory.getClass().getName();NacosRestTemplate nacosRestTemplate = SINGLETON_REST.get(factoryName);if (nacosRestTemplate == null) {synchronized (SINGLETON_REST) {nacosRestTemplate = SINGLETON_REST.get(factoryName);if (nacosRestTemplate != null) {return nacosRestTemplate;}//  如果SINGLETON_REST 这个集合中没有找到,会走到这个方法,会发现 参数传过来的 httpClientFactory是个接口,并且有两个实现类,分别是AbstractApacheHttpClientFactory和AbstractHttpClientFactory,因为知道入参其实就是NamingHttpClientFactory,并且继承了AbstractHttpClientFactorynacosRestTemplate = httpClientFactory.createNacosRestTemplate();SINGLETON_REST.put(factoryName, nacosRestTemplate);}}return nacosRestTemplate;}AbstractHttpClientFactory类HttpClientConfig httpClientConfig = buildHttpClientConfig();// 这里就知道NacosRestTemplate中的HttpClientRequest属性其实是  JdkHttpClientRequest实例对象,final JdkHttpClientRequest clientRequest = new JdkHttpClientRequest(httpClientConfig);// enable sslinitTls(new BiConsumer() {@Overridepublic void accept(SSLContext sslContext, HostnameVerifier hostnameVerifier) {clientRequest.setSSLContext(loadSSLContext());clientRequest.replaceSSLHostnameVerifier(hostnameVerifier);}}, new TlsFileWatcher.FileChangeListener() {@Overridepublic void onChanged(String filePath) {clientRequest.setSSLContext(loadSSLContext());}});return new NacosRestTemplate(assignLogger(), clientRequest);}

NacosRestTemplate类

在上面NamingProxy中一顿点击之后,会调用到NacosRestTemplate的execute方法,如下

    private  HttpRestResult execute(String url, String httpMethod, RequestHttpEntity requestEntity,Type responseType) throws Exception {URI uri = HttpUtils.buildUri(url, requestEntity.getQuery());if (logger.isDebugEnabled()) {logger.debug("HTTP method: {}, url: {}, body: {}", httpMethod, uri, requestEntity.getBody());}ResponseHandler responseHandler = super.selectResponseHandler(responseType);HttpClientResponse response = null;try {/// 上面溯源得到的  JdkHttpClientRequest  对应的就是this.requestClient(),因为上面可以看到调用NacosRestTemplate的构造函数,传入的是JdkHttpClientRequest  response = this.requestClient().execute(uri, httpMethod, requestEntity);return responseHandler.handle(response);} finally {if (response != null) {response.close();}}}

之后就是使用HttpURLConnection实际发情请求,并且处理Response了。

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...