准备部分
这是在真正调用注册实例的方法之前,需要使用到的对象的关系图。
源码跟踪
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 {
@Bean
public NacosServiceRegistry nacosServiceRegistry(
// 在spring.factories中,有个自动创建的类是 NacosServiceAutoConfiguration,这个类里创建了 NacosServiceManager 对象,也就是对应这里的第一个参数
NacosServiceManager nacosServiceManager,
NacosDiscoveryProperties nacosDiscoveryProperties) { // 取的配置文件
return new NacosServiceRegistry(nacosServiceManager, nacosDiscoveryProperties);
}
@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
public NacosRegistration nacosRegistration(
ObjectProvider<List<NacosRegistrationCustomizer>> registrationCustomizers, // 不知道是个啥,感觉不是重点所以没看
NacosDiscoveryProperties nacosDiscoveryProperties, // 配置文件
ApplicationContext context) { // spring容器创建的
return new NacosRegistration(registrationCustomizers.getIfAvailable(),
nacosDiscoveryProperties, context);
}
@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
这个是才是重点对象
public NacosAutoServiceRegistration nacosAutoServiceRegistration(
NacosServiceRegistry registry, // 上面第一个方法创建的Bean
AutoServiceRegistrationProperties autoServiceRegistrationProperties, // 取的配置文件中的值
NacosRegistration registration) { // 上面第二个方法创建的Bean
return new NacosAutoServiceRegistration(registry,
autoServiceRegistrationProperties, registration);
}
}
AbstractAutoServiceRegistration类
直接看NacosAutoServiceRegistration继承的这个抽象类
@Override
@SuppressWarnings("deprecation")
// NacosAutoServiceRegistration类有实现ApplicationListener<WebServerInitializedEvent>,所以会监听到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)方法,
@Override
public 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<String, String> params, Map<String, String> 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<String> 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,并且继承了AbstractHttpClientFactory
nacosRestTemplate = httpClientFactory.createNacosRestTemplate();
SINGLETON_REST.put(factoryName, nacosRestTemplate);
}
}
return nacosRestTemplate;
}
AbstractHttpClientFactory类
HttpClientConfig httpClientConfig = buildHttpClientConfig();
// 这里就知道NacosRestTemplate中的HttpClientRequest属性其实是 JdkHttpClientRequest实例对象,
final JdkHttpClientRequest clientRequest = new JdkHttpClientRequest(httpClientConfig);
// enable ssl
initTls(new BiConsumer<SSLContext, HostnameVerifier>() {
@Override
public void accept(SSLContext sslContext, HostnameVerifier hostnameVerifier) {
clientRequest.setSSLContext(loadSSLContext());
clientRequest.replaceSSLHostnameVerifier(hostnameVerifier);
}
}, new TlsFileWatcher.FileChangeListener() {
@Override
public void onChanged(String filePath) {
clientRequest.setSSLContext(loadSSLContext());
}
});
return new NacosRestTemplate(assignLogger(), clientRequest);
}
NacosRestTemplate类
在上面NamingProxy中一顿点击之后,会调用到NacosRestTemplate的execute方法,如下
private <T> HttpRestResult<T> 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<T> 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了。