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. 【高并发】AQS中的CountDownLatch、Semaphore与CyclicBarrier用法总结

    CountDownLatch 概述 同步辅助类,通过它可以阻塞当前线程.也就是说,能够实现一个线程或者多个线程一直等待,直到其他线程执行的操作完成.使用一个给定的计数器进行初始化,该计数器的操作是原子 ...

  2. 财务精度:BigInteger 与 BigDecimal

    财务精度:BigInteger 与 BigDecimal 每博一文案 师父说: 人这一辈子,真地好难. 有些人,好着好着,忽然就变陌生了,有些手,牵着牵着,瞬间就放开了,有些路,走着走着,就失去了方向 ...

  3. activemq插件在eos中的开发

    ActiceMQ-CPP消息插件是CMS的一种实现,是一个能够与ActiveMQ进行通信的C++客户端库,ActiveMQ-CPP的架构设计能够支持可插拨的传输协议和消息封装格式,并且支持客户端容量, ...

  4. Android第五次作业

    <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android=&q ...

  5. Nacos配置中心 (介绍与配置)

    Nacos配置中心 当微服务部署的实例越来越多,达到数十.数百时,逐个修改微服务配置就会让人抓狂,而且很容易出错.我们需要一种统一配置管理方案,可以集中管理所有实例的配置. Nacos一方面可以将配置 ...

  6. C#网络爬虫开发

    1前言 爬虫一般都是用Python来写,生态丰富,动态语言开发速度快,调试也很方便 但是 我要说但是,动态语言也有其局限性,笔者作为老爬虫带师,几乎各种语言都搞过,现在这个任务并不复杂,用我最喜欢的C ...

  7. P19_数据绑定

    数据绑定 数据绑定的基本原则 在 data 中定义数据 在 WXML 中使用数据 在 data 中定义页面的数据 在页面对应的 .js 文件中,把数据定义到 data 对象中即可: Mustache ...

  8. Cannot find module ‘xxx\node_modules\yorkie\bin\install.js‘

    1.出现问题原因 安装一个新仓库代码的依赖包,如输入npm install或yarn install,出现如题错误 2.解决办法 1)升级node.js 下载地址:https://nodejs.org ...

  9. Node Sass could not find a binding for your current environment: Windows 64-bit with Node.js 1x.x

    出现问题原因: nodejs和node-sass版本不匹配 解决办法: 下载node-sass指定版本的nodejs 1)node-sass的节点版本支持政策 ① 支持的 Node.js版本因版本而异 ...

  10. Java前后端请求Content-Type与接受方式

    1.Get Get方法没有请求体,所以加不加Content-Type没有意义. 参数通过拼接到Url来加入 url?key=value&key2=value2 SpringMVC后台如何获取参 ...