Eureka Server启动过程

入口:SpringCloud充分利用了SpringBoot的自动装配的特点
  • 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)的更多相关文章

  1. Spring Cloud微服务笔记(二)Spring Cloud 简介

    Spring Cloud 简介 Spring Cloud的设计理念是Integrate Everything,即充分利用现有的开源组件, 在它们之上设计一套统一的规范/接口使它们能够接入Spring ...

  2. Spring Cloud微服务笔记(三)服务治理:Spring Cloud Eureka快速入门

    服务治理:Spring Cloud Eureka 一.服务治理 服务治理是微服务架构中最为核心和基础的模块,它主要用来实现各个微服务实例的自动化注册与发现. 1.服务注册: 在服务治理框架中,通常会构 ...

  3. Spring Cloud微服务笔记(一)微服务概念

    微服务概念 一.什么是微服务架构 微服务,是一个小的.松耦合的分布式服务. 为什么需要微服务: 1)单体系统部署在一个进程中,修改了一个小功能,为了部署上线就会影响其他功能. 2)单体应用各个功能模块 ...

  4. SpringCloud微服务笔记-Nginx实现网关反向代理

    背景 当前在SpringCloud微服务架构下,网关作为服务的入口尤为重要,一旦网关发生单点故障会导致整个服务集群瘫痪,为了保证网关的高可用可以通过Nginx的反向代理功能实现网关的高可用. 项目源码 ...

  5. Spring Cloud 微服务笔记(七) Zuul入门

    Zuul入门 Zuul是从设备和网站到后端应用程序所有请求的前门,为内部服务提供可配置的对外URL到服务的 映射关系,基于JVM的后端路由器.其具备一下功能: 1)认证与授权 2)压力控制 3)金丝雀 ...

  6. Spring Cloud 微服务笔记(六)Spring Cloud Hystrix

    Spring Cloud Hystrix Hystrix是一个延迟和容错库,旨在隔离远程系统.服务和第三方库,阻止链接故障,在复杂的分布式系统中实现恢复能力. 一.快速入门 1)依赖: <dep ...

  7. Spring Cloud微服务笔记(五)Feign

    Feign 一.Feign概述 Feign是一个声明式的Web Service客户端.在Spring Cloud 中使用Feign,可以做到 使用HTTP请求访问远程服务,就像调用本地方法一样,同时它 ...

  8. Spring Cloud微服务笔记(四)客户端负载均衡:Spring Cloud Ribbon

    客户端负载均衡:Spring Cloud Ribbon 一.负载均衡概念 负载均衡在系统架构中是一个非常重要,并且是不得不去实施的内容.因为负载均衡对系统的高可用性. 网络压力的缓解和处理能力的扩容的 ...

  9. 将微服务注册到Euraka

    1.添加依赖 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId> ...

  10. 一起学习 微服务(MicroServices)-笔记

    笔记 微服务特性: 1. 小 专注与做一件事(适合团队就是最好的) 2. 松耦合 独立部署 3. 进程独立 4. 轻量级通信机制 实践: 1. 微服务周边的一系列基础建设 Load Balancing ...

随机推荐

  1. Java入门与进阶P-5.1+P-5.2

    初识数组 一.数组 数组是用来存储一个元素个数固定且元素类型相同·的有序集. 数组的两个特点:大小是固定的,且确定之后是不能改变的:数组内的元素类型是相同的. 1.数组的定义(两种): int arr ...

  2. ChatGpt国内教程

    近ChatGPT大火呀,小伙伴们是不是在网上看到各种和ChatGPT有趣聊天的截图,比如翻译代码.编写代码,奈何自己实力不够,被网络拒之门外,只能眼馋别人的东西.看别人玩,肯定不如自己玩一把舒服的啊. ...

  3. springboot多模块controller访问的问题

    参考 https://blog.csdn.net/qq_25091649/article/details/88429512 情况一:在主类直接写controller接口,能够访问到 @SpringBo ...

  4. 【Vue】style和class 列表渲染 使用v-for进行循环 监控失效 双向数据绑定 过滤案例 事件修饰符

    目录 昨日回顾 style和class class属性的三种设置方法 style属性的三种设置方法 条件渲染 列表渲染 使用v-for进行循环 循环数字 循环字符串 循环对象 循环数组 标签key值加 ...

  5. C#中的Byte,String,Int,Hex之间的转换函数

    /// <summary> Convert a string of hex digits (ex: E4 CA B2) to a byte array. </summary> ...

  6. UBUNTU18.04安装Pangolin

    https://github.com/stevenlovegrove/Pangolin

  7. Java期末测试

    会议预约管理信息系统(50分)     1.项目背景: 会议是企业进行决策.协商的重要组织形式,是企业日常办公处理事务的重要手段,是办公流程中不可缺少的重要环节,作为企业,如何有效的进行会议组织,管理 ...

  8. ES6的Set详解

    数组去重 let arr = [ 1,2,3,4,5,3,2 ] // 数组去重 // 方法一 let newArr = [new Set(arr)] console.log(newArr); // ...

  9. OpenLayers集成ECharts

    1. 引言 OpenLayers是WebGIS中常用的开源JavaScript前端库,ECharts是常用的可视化开源JavaScript前端库 OpenLayers官网:OpenLayers - W ...

  10. Postgresql动态共享内存类型

    一.简介 linux为多个进程通信提供了不同的IPC机制,如:System V , POSIX 和 MMAP,所以Postgresql共享内存管理也支持以上类型. 在Postgresql中可以使用dy ...