微服务笔记之Euraka(2)
Eureka Server启动过程
- Eureka-server的jar包,发现在MERA-INF下面有配置文件spring.factories
SpringBoot应用启动时会加载EurekaServerAutoConfiguration自动配置
EurekaServerAutoConfiguration类
先看头部信息
@Configuration
@Import(EurekaServerInitializerConfiguration.class) //导入初始化类
@ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class) //加载Bean对象----> Marker
@EnableConfigurationProperties({ EurekaDashboardProperties.class,
InstanceRegistryProperties.class })
@PropertySource("classpath:/eureka/server.properties") // 配置类和配置信息
public class EurekaServerAutoConfiguration extends WebMvcConfigurerAdapter {
//...
}
主要分析EurekaServerInitializerConfiguration、Marker、EurekaServerAutoConfiguration这三个类
1、先看Marker这个类,它是什么时候注入的?
其实是由@EnableEurekaServer注解决定的,如下:
@SpringBootApplication
@EnableEurekaServer //在我们启动类添加该注解,声明是一个EurekaServer
public class EurekaApplication { public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
进入EnableEurekaServer注解,会发现他导入了一个EurekaServerMarkerConfiguration类
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(EurekaServerMarkerConfiguration.class) // 导入该类,和我们的Marker类很相像
public @interface EnableEurekaServer { }
再进入EurekaServerMarkerConfiguration类,在该类中将Marker注入到容器中
@Configuration
public class EurekaServerMarkerConfiguration { @Bean // 此处将Marker注入到容器中
public Marker eurekaServerMarkerBean() {
return new Marker();
} class Marker {
}
}
但是Marker这个类什么都没写,不知道导入它有什么用???
2、再看EurekaServerAutoConfiguration这个类
主要分析以下几个重要的方法
eurekaController这个方法:它注入一个对外的接口(通过这个接口我们可以访问后台界面),这个后台界面我们可以通过配置来修改它是否让它显示,在配置文件中加入eureka.dashboard.enabled = false即可
@Bean
@ConditionalOnProperty(prefix = "eureka.dashboard", name = "enabled", matchIfMissing = true)
public EurekaController eurekaController() {
return new EurekaController(this.applicationInfoManager);
}
后台界面就是下图

peerAwareInstanceRegistry这个方法:它是对等节点感知实例注册器,在集群模式下,注册服务使用到的注册器
@Bean
public PeerAwareInstanceRegistry peerAwareInstanceRegistry(
ServerCodecs serverCodecs) {
this.eurekaClient.getApplications(); // force initialization
return new InstanceRegistry(this.eurekaServerConfig, this.eurekaClientConfig,serverCodecs, this.eurekaClient, this.instanceRegistryProperties.getExpectedNumberOfClientsSendingRenews(),
this.instanceRegistryProperties.getDefaultOpenForTrafficCount());
}
peerEurekaNodes这个方法:它的作用是注入对等的实例节点信息,辅助封装对等节点相关的信息和操作。在EurekaServer集群中,更新集群中对等的节点,因为EurekaServer集群节点可能发生变化,更新节点在PeerEurekaNodes类中的start方法中实现
@Bean
@ConditionalOnMissingBean
public PeerEurekaNodes peerEurekaNodes(PeerAwareInstanceRegistry registry,
ServerCodecs serverCodecs) {
return new RefreshablePeerEurekaNodes(registry, this.eurekaServerConfig,this.eurekaClientConfig,serverCodecs, this.applicationInfoManager);
}
PeerEurekaNodes类中的start方法
public void start() {
this.taskExecutor = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
public Thread newThread(Runnable r) {
Thread thread = new Thread(r, "Eureka-PeerNodesUpdater");
thread.setDaemon(true);
return thread;
}
});
try {
this.updatePeerEurekaNodes(this.resolvePeerUrls());
Runnable peersUpdateTask = new Runnable() {
public void run() {
try {
// 该方法进行更新节点
PeerEurekaNodes.this.updatePeerEurekaNodes(PeerEurekaNodes.this.resolvePeerUrls());
} catch (Throwable var2) {
PeerEurekaNodes.logger.error("Cannot update the replica Nodes", var2);
}
}
};
this.taskExecutor.scheduleWithFixedDelay(peersUpdateTask, (long)this.serverConfig.getPeerEurekaNodesUpdateIntervalMs(), (long)this.serverConfig.getPeerEurekaNodesUpdateIntervalMs(), TimeUnit.MILLISECONDS);
} catch (Exception var3) {
throw new IllegalStateException(var3);
}
Iterator var4 = this.peerEurekaNodes.iterator();
while(var4.hasNext()) {
PeerEurekaNode node = (PeerEurekaNode)var4.next();
logger.info("Replica node URL: {}", node.getServiceUrl());
}
}
那么什么时候执行start方法呢?且往下看
eurekaServerContext这个方法:注入EurekaServer的上下文对象,返回的是一个DefaultEurekaServerContext对象,
@Bean
public EurekaServerContext eurekaServerContext(ServerCodecs serverCodecs,PeerAwareInstanceRegistry registry, PeerEurekaNodes peerEurekaNodes) {
return new DefaultEurekaServerContext(this.eurekaServerConfig, serverCodecs,registry, peerEurekaNodes, this.applicationInfoManager);
}
DefaultEurekaServerContext类中有个Initialize方法,他会在DefaultEurekaServerContext初始化完成后执行,在它里面会执行上述的start方法
@PostConstruct
public void initialize() {
logger.info("Initializing ...");
this.peerEurekaNodes.start();
try {
this.registry.init(this.peerEurekaNodes);
} catch (Exception var2) {
throw new RuntimeException(var2);
}
logger.info("Initialized");
}
eurekaServerBootstrap这个方法:注入一个EurekaServerBootstrap对象,后续启动会使用该对象
@Bean
public EurekaServerBootstrap eurekaServerBootstrap(PeerAwareInstanceRegistry registry,EurekaServerContext serverContext) {
return new EurekaServerBootstrap(this.applicationInfoManager, this.eurekaClientConfig, this.eurekaServerConfig, registry,serverContext);
}
jerseyFilterRegistration这个方法:它会注册Jersey过滤器。Jersey它是一个rest框架,帮我们发布resetful服务接口的(类似于springmvc)。EurekaServer端和EurekaClient进行通信,Server端发送的是http服务,该服务就是由Jersey发送。
@Bean
public FilterRegistrationBean jerseyFilterRegistration(
javax.ws.rs.core.Application eurekaJerseyApp) {
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new ServletContainer(eurekaJerseyApp));
bean.setOrder(Ordered.LOWEST_PRECEDENCE);
bean.setUrlPatterns(Collections.singletonList(EurekaConstants.DEFAULT_PREFIX + "/*"));
return bean;
}
jerseyApplication这个方法:它会注入一个Application对象,它的作用就是作为jerseyFilterRegistration方法的参数注册Jersey过滤器
@Bean
public javax.ws.rs.core.Application jerseyApplication(Environment environment,ResourceLoader resourceLoader) {
//...
}
3、再看EurakaServerInitializerConfiguration这个类
它实现了SmartLifecycle这个接口,该接口的父类是Lifecycle(此接口中有一个start方法),实现该接口,可以在Spring容器的Bean创建完成之后做一些事情(如执行start方法)
@Configuration
public class EurekaServerInitializerConfiguration implements ServletContextAware, SmartLifecycle, Ordered {
//...
}
下面我们看一下start方法实现(其中上面我们所讲的EurekaServerBootStrap注册的对象就是在此处使用的)
@Override
public void start() {
new Thread(new Runnable() {
@Override
public void run() {
try {
//TODO: is this class even needed now?
// 初始化EurekaServerContext细节
eurekaServerBootstrap.contextInitialized(EurekaServerInitializerConfiguration.this.servletContext);
log.info("Started Eureka Server");
// 发布事件
publish(new EurekaRegistryAvailableEvent(getEurekaServerConfig()));
// 状态属性设置
EurekaServerInitializerConfiguration.this.running = true;
// 发布事件
publish(new EurekaServerStartedEvent(getEurekaServerConfig()));
}catch (Exception ex) {
// Help!
log.error("Could not initialize Eureka servlet context", ex);
}
}
}).start();
}
下面看一下contextInitialized这个方法
public void contextInitialized(ServletContext context) {
try {
// 初始化环境信息
initEurekaEnvironment();
// 初始化context细节
initEurekaServerContext();
context.setAttribute(EurekaServerContext.class.getName(), this.serverContext);
}catch (Throwable e) {
log.error("Cannot bootstrap eureka server :", e);
throw new RuntimeException("Cannot bootstrap eureka server :", e);
}
}
看一下initEurekaServerContext这个方法
protected void initEurekaServerContext() throws Exception {
// For backward compatibility
JsonXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(),XStream.PRIORITY_VERY_HIGH);
XmlXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(),XStream.PRIORITY_VERY_HIGH);
if (isAws(this.applicationInfoManager.getInfo())) {
this.awsBinder = new AwsBinderDelegate(this.eurekaServerConfig,
this.eurekaClientConfig, this.registry, this.applicationInfoManager);
this.awsBinder.start();
}
// 此处是给非IOC容器提供获取EurekaServerContext对象的接口
EurekaServerContextHolder.initialize(this.serverContext);
log.info("Initialized server context");
// 某一个server实例启动的时候,从集群中其他的server拷贝注册信息过来(同步其他节点信息),每一个server对于其他server来说也是一个客户端
int registryCount = this.registry.syncUp();
// 更改实例状态为UP,对外提供服务
this.registry.openForTraffic(this.applicationInfoManager, registryCount);
// 注册统计器
EurekaMonitors.registerAllStats();
}
先看一下syncUp这个方法
public int syncUp() {
// Copy entire entry from neighboring DS node
int count = 0; // 统计节点个数
// serverConfig.getRegistrySyncRetries() 可能由于远程server没有连接上,做重试操作
for (int i = 0; ((i < serverConfig.getRegistrySyncRetries()) && (count == 0)); i++) {
if (i > 0) {
try {
Thread.sleep(serverConfig.getRegistrySyncRetryWaitMs());
} catch (InterruptedException e) {
logger.warn("Interrupted during registry transfer..");
break;
}
}
// 获取其他server的注册表信息
Applications apps = eurekaClient.getApplications();
for (Application app : apps.getRegisteredApplications()) {
for (InstanceInfo instance : app.getInstances()) {
try {
if (isRegisterable(instance)) {
// 把从远程获取到的注册表信息注册到自己的注册表中(map)
register(instance, instance.getLeaseInfo().getDurationInSecs(), true);
count++;
}
} catch (Throwable t) {
logger.error("During DS init copy", t);
}
}
}
}
return count;
}
看一下register方法

回过头来在看一下openForTraffic方法

以上就是EurekaServer启动过程分析
微服务笔记之Euraka(2)的更多相关文章
- Spring Cloud微服务笔记(二)Spring Cloud 简介
Spring Cloud 简介 Spring Cloud的设计理念是Integrate Everything,即充分利用现有的开源组件, 在它们之上设计一套统一的规范/接口使它们能够接入Spring ...
- Spring Cloud微服务笔记(三)服务治理:Spring Cloud Eureka快速入门
服务治理:Spring Cloud Eureka 一.服务治理 服务治理是微服务架构中最为核心和基础的模块,它主要用来实现各个微服务实例的自动化注册与发现. 1.服务注册: 在服务治理框架中,通常会构 ...
- Spring Cloud微服务笔记(一)微服务概念
微服务概念 一.什么是微服务架构 微服务,是一个小的.松耦合的分布式服务. 为什么需要微服务: 1)单体系统部署在一个进程中,修改了一个小功能,为了部署上线就会影响其他功能. 2)单体应用各个功能模块 ...
- SpringCloud微服务笔记-Nginx实现网关反向代理
背景 当前在SpringCloud微服务架构下,网关作为服务的入口尤为重要,一旦网关发生单点故障会导致整个服务集群瘫痪,为了保证网关的高可用可以通过Nginx的反向代理功能实现网关的高可用. 项目源码 ...
- Spring Cloud 微服务笔记(七) Zuul入门
Zuul入门 Zuul是从设备和网站到后端应用程序所有请求的前门,为内部服务提供可配置的对外URL到服务的 映射关系,基于JVM的后端路由器.其具备一下功能: 1)认证与授权 2)压力控制 3)金丝雀 ...
- Spring Cloud 微服务笔记(六)Spring Cloud Hystrix
Spring Cloud Hystrix Hystrix是一个延迟和容错库,旨在隔离远程系统.服务和第三方库,阻止链接故障,在复杂的分布式系统中实现恢复能力. 一.快速入门 1)依赖: <dep ...
- Spring Cloud微服务笔记(五)Feign
Feign 一.Feign概述 Feign是一个声明式的Web Service客户端.在Spring Cloud 中使用Feign,可以做到 使用HTTP请求访问远程服务,就像调用本地方法一样,同时它 ...
- Spring Cloud微服务笔记(四)客户端负载均衡:Spring Cloud Ribbon
客户端负载均衡:Spring Cloud Ribbon 一.负载均衡概念 负载均衡在系统架构中是一个非常重要,并且是不得不去实施的内容.因为负载均衡对系统的高可用性. 网络压力的缓解和处理能力的扩容的 ...
- 将微服务注册到Euraka
1.添加依赖 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId> ...
- 一起学习 微服务(MicroServices)-笔记
笔记 微服务特性: 1. 小 专注与做一件事(适合团队就是最好的) 2. 松耦合 独立部署 3. 进程独立 4. 轻量级通信机制 实践: 1. 微服务周边的一系列基础建设 Load Balancing ...
随机推荐
- golang主协程等待子协程执行完毕
无限等待 计时等待 channel通信 select 等待组
- Python求取文件夹内的文件数量、子文件夹内的文件数量
本文介绍基于Python语言,统计文件夹中文件数量:若其含有子文件夹,还将对各子文件夹中的文件数量一并进行统计的方法. 最近,需要统计多个文件夹内部的文件数量,包括其中所含子文件夹中的文件数量 ...
- 9月22日内容总结——计算机五大组成部分详解、编程语言及发展史、python解释器安装与环境变量设置
内容总结 目录 内容总结 一.计算机五大组成部分详细介绍 1.控制器 2.运算器 3.存储设备 4.输入设备 5.输出设备 二.计算机三大核心硬件 1. cpu 2.内存 举例:写文档时,突然关机了. ...
- python3中,isinstance() 函数
#isinstance() 函数来判断一个对象是否是一个已知的类型,类似 type(). #返回值:如果对象的类型与参数二的类型相同则返回True,否则返回False 使用isinstance函数的实 ...
- Seata分布式事务
使用Seata版本:1.6.1(2023/2/6最新版)该版本存在很多坑,相较于1.0版本,配置上存在很多差别,如果你的版本不同,请不要参考本文. 1.6.1配置存在许多问题,比较难找,如果你使用1. ...
- 快学会这个技能-.NET API拦截技法
大家好,我是沙漠尽头的狼. 本文先抛出以下问题,请在文中寻找答案,可在评论区回答: 什么是API拦截? 一个方法被很多地方调用,怎么在不修改这个方法源码情况下,记录这个方法调用的前后时间? 同2,不修 ...
- 【Oculus Interaction SDK】(十二)Meta Quest 如何开启透视(Passthrough)
前言 前段时间 Oculus 的 SDK 频繁更新,很多已有的教程都不再适用于现在的版本了.本系列文章的主要目的是记录现版本常见功能的实现方法,便于自己后续开发.当然,不排除我文章刚写完 SDK 又变 ...
- K8s 网络新手教程(Kubernetes Networking Guide for Beginners)
K8s 网络新手教程(Kubernetes Networking Guide for Beginners) 原文链接: Kubernetes Networking Guide for Beginner ...
- windows server backup 无法使用或wbadmin.msc致命错误解决方法
因为黑群辉断电无法自动引导进系统,我也找不到很好的办法,所以决定使用windows server来做NAS服务器,虽然都解决了内网穿透的问题,但是数据安全还在找方案,目前已经解决: 1.购买了一张pc ...
- 2020-6-2 map?
问题描述 试题编号: 202006-2 试题名称: 稀疏向量 时间限制: 2.0s 内存限制: 512.0MB 问题描述: #include<stdio.h>//数据量很大,所 ...