Eureka 系列(03)Spring Cloud 自动装配原理

0. Spring Cloud 系列目录 - Eureka 篇

本文主要是分析 Spring Cloud 是如何整合 Eureka 的,但不会具体分析 Eureka 的源码,之后的文章会对 Eureka 的源码做一个比较具体的分析。

1. Eureka Client 自动装配

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration,\
org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration

图1:Eureka Client 自动装配时序图

sequenceDiagram
participant EurekaClientAutoConfiguration
participant EurekaDiscoveryClientConfiguration
participant CloudEurekaClient
participant EurekaAutoServiceRegistration
EurekaClientAutoConfiguration ->> CloudEurekaClient : @Bean
EurekaDiscoveryClientConfiguration ->> EurekaAutoServiceRegistration : @Bean
EurekaAutoServiceRegistration ->> CloudEurekaClient : register

总结: Eureka Client 的装配很简单,主要是组装 DiscoveryClient。

  • EurekaClientAutoConfiguration 主要是装配 EurekaClient
  • EurekaDiscoveryClientConfiguration 主要是在 Eureka Client 启动时立即将自身注册到 Eureka Server 上。

1.1 装配 DiscoveryClient

EurekaClientAutoConfiguration 主要是装配 CloudEurekaClient,CloudEurekaClient 继承了 DiscoveryClient,主要是增加了 Spring 的事件机制。

@Bean(destroyMethod = "shutdown")
public EurekaClient eurekaClient(ApplicationInfoManager manager,
EurekaClientConfig config, EurekaInstanceConfig instance,
@Autowired(required = false) HealthCheckHandler healthCheckHandler) {
CloudEurekaClient cloudEurekaClient = new CloudEurekaClient(
appManager, config, this.optionalArgs, this.context);
cloudEurekaClient.registerHealthCheck(healthCheckHandler);
return cloudEurekaClient;
}

1.2 启动时立即注册

EurekaDiscoveryClientConfiguration 主要是实现了自动注册。在 DiscoveryClient 中默认是启动 40s 后才会注册,延迟太长,Spring Cloud 改变了这种默认实现,在启动时调用 EurekaAutoServiceRegistration.start() ,将自身实例注册到 Eureka Server 上。

// EurekaAutoServiceRegistration 启动时自动注册
public void start() {
if (!this.running.get() && this.registration.getNonSecurePort() > 0) {
// 启动时自动注册
this.serviceRegistry.register(this.registration);
this.context.publishEvent(new InstanceRegisteredEvent<>(this, this.registration.getInstanceConfig()));
this.running.set(true);
}
}

1.3 替换 EurekaHttpClient

Spring Cloud 实现了自己的 RestTemplateEurekaHttpClient,可以替换默认的 JerseyApplicationClient。DiscoveryClientOptionalArgsConfiguration 中装配条件如下:

@Bean
@ConditionalOnMissingClass("com.sun.jersey.api.client.filter.ClientFilter")
@ConditionalOnMissingBean(value = AbstractDiscoveryClientOptionalArgs.class, search = SearchStrategy.CURRENT)
public RestTemplateDiscoveryClientOptionalArgs restTemplateDiscoveryClientOptionalArgs() {
return new RestTemplateDiscoveryClientOptionalArgs();
}

查一下 com.sun.jersey 的依赖情况,可以看到 eureka-client 默认会引入 jersey-client,也就是说会使用默认的 JerseyApplicationClient。

>mvn dependency:tree -Dincludes="com.sun.jersey"
[INFO] com.github.binarylei.springcloud:user-consumer-eureka-client:jar:1.0.0
[INFO] \- org.springframework.cloud:spring-cloud-starter-netflix-eureka-client:jar:2.1.1.RELEASE:compile
[INFO] \- com.netflix.eureka:eureka-client:jar:1.9.8:compile
[INFO] +- com.sun.jersey:jersey-core:jar:1.19.1:runtime
[INFO] \- com.sun.jersey:jersey-client:jar:1.19.1:runtime

既然知道了原因,要替换为 RestTemplateEurekaHttpClient 就很简单了。

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<exclusions>
<exclusion>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
</exclusion>
</exclusions>
</dependency>

分析了客户自动装配后,接下来继续分析 Eureka Server 服务端的启动原理,Eureka 服务端的启动同样依赖 DiscoverClient(个人感觉依赖有点混乱)。

2. Eureka Server 自动装配

在原生的 Eureka 中服务端的启动类是 EurekaBootStrap,Spring Cloud 中启动类是 EurekaServerBootstrap,原理大致都差不多。本文会以 EurekaServerBootstrap 为切入点进行分析。

EurekaServerAutoConfiguration 是 Spring Cloud 自动装配入口,配置如下:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.netflix.eureka.server.EurekaServerAutoConfiguration

注意: EurekaServerAutoConfiguration 需要配合 @EnableEurekaServer 使用。

2.1 Eureka Server 自动装配流程

图2:Eureka Server 自动装配时序图

sequenceDiagram
participant EurekaServerAutoConfiguration
participant EurekaServerInitializerConfiguration
participant PeerAwareInstanceRegistry
participant PeerEurekaNodes
participant EurekaServerBootstrap
participant EurekaClient
EurekaServerAutoConfiguration ->> PeerAwareInstanceRegistry : @Bean
EurekaServerAutoConfiguration ->> PeerEurekaNodes : @Bean
EurekaServerAutoConfiguration ->> EurekaServerBootstrap : @Bean
EurekaServerAutoConfiguration ->> EurekaServerInitializerConfiguration : @Import
loop Eureka Server 服务启动
EurekaServerInitializerConfiguration ->> EurekaServerInitializerConfiguration : start
EurekaServerInitializerConfiguration ->> EurekaServerBootstrap : contextInitialized
EurekaServerBootstrap ->> PeerAwareInstanceRegistry : 1. 从其它服务器同步数据:syncUp
PeerAwareInstanceRegistry ->> EurekaClient : 获取其它服务器的数据:getApplications
EurekaServerBootstrap ->> PeerAwareInstanceRegistry : 2. 启动自动过期定时任务:openForTraffic
end
loop Eureka Server 服务销毁
EurekaServerInitializerConfiguration ->> EurekaServerInitializerConfiguration : stop
EurekaServerInitializerConfiguration ->> EurekaServerBootstrap : contextDestroyed
end

总结: Spring Cloud 有个特点,一般来说类的职责都很明确。

  1. EurekaServerAutoConfiguration 主要是装配 EurekaServerBootstrap
  2. EurekaServerInitializerConfiguration 则负责启动 EurekaServerBootstrap
  3. EurekaServerBootstrap 启动时主要完成两件事:一是从其它 Eureka Server 上同步数据;二是启动自动过期定时任务 EvictionTask。可以看到 Eureka 最核心的数据结构是 PeerAwareInstanceRegistry。

Eureka Server 核心实现类:

  • PeerAwareInstanceRegistry 负责 Eureka Server 之间数据同步,其父类 AbstractInstanceRegistry 则管理所有的本地注册信息。
  • PeerEurekaNodes 负责 Eureka Server 服务器列表管理。
  • EurekaServerBootstrap 启动类。
  • EurekaClient 上文提到 Eureka Server 启动是要依赖 Eureka Client 客户端,所以也会自动装配 EurekaClient,启动时同步数据会依赖 EurekaClient。

2.2 EurekaServerBootstrap

EurekaServerInitializerConfiguration 实现了 SmartLifecycle 接口,也就是启动和销毁时会分别调用 start 和 stop 方法。

public void start() {
new Thread(new Runnable() {
@Override
public void run() {
try {
// TODO: is this class even needed now?
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();
} public void stop() {
this.running = false;
eurekaServerBootstrap.contextDestroyed(this.servletContext);
}

继续关注 EurekaServerBootstrap 的 contextInitialized 和 contextDestroyed 方法分别完成了什么事情。

public void contextInitialized(ServletContext context) {
initEurekaEnvironment();
initEurekaServerContext();
} protected void initEurekaServerContext() throws Exception {
...
// Copy registry from neighboring eureka node
int registryCount = this.registry.syncUp();
this.registry.openForTraffic(this.applicationInfoManager, registryCount); // Register all monitoring statistics.
EurekaMonitors.registerAllStats();
}

总结: 可以看到 EurekaServerBootstrap 启动时主要步骤:一是同步数据;二是启动定时过期的任务 EvictionTask。具体的源码会在之后分析。


每天用心记录一点点。内容也许不重要,但习惯很重要!

Eureka 系列(03)Spring Cloud 自动装配原理的更多相关文章

  1. Spring Boot 自动装配原理

    Spring Boot 自动装配原理 Spring Boot 在启动之前还有一系列的准备工作,比如:推断 web 应用类型,设置初始化器,设置监听器,启动各种监听器,准备环境,创建 applicati ...

  2. Spring Boot系列(二):Spring Boot自动装配原理解析

    一.Spring Boot整合第三方组件(Redis为例) 1.加依赖 <!--redis--> <dependency> <groupId>org.springf ...

  3. 从源码中理解Spring Boot自动装配原理

    个人博客:槿苏的知识铺 一.什么是自动装配 SpringBoot 定义了一套接口规范,这套规范规定:SpringBoot在启动时会扫描外部引用jar包中的META-INF/spring.factori ...

  4. spring的自动装配,骚话@Autowired的底层工作原理

    前言 开心一刻 十年前,我:我交女票了,比我大两岁.妈:不行!赶紧分! 八年前,我:我交女票了,比我小两岁,外地的.妈:你就不能让我省点心? 五年前,我:我交女票了,市长的女儿.妈:别人还能看上你?分 ...

  5. SpringBoot启动流程分析(五):SpringBoot自动装配原理实现

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  6. Spring Boot自动配置原理(转)

    第3章 Spring Boot自动配置原理 3.1 SpringBoot的核心组件模块 首先,我们来简单统计一下SpringBoot核心工程的源码java文件数量: 我们cd到spring-boot- ...

  7. 撸一撸Spring Cloud Ribbon的原理-负载均衡器

    在上一篇<撸一撸Spring Cloud Ribbon的原理>中整理发现,RestTemplate内部调用负载均衡拦截器,拦截器内最终是调用了负载均衡器来选择服务实例. 接下来撸一撸负载均 ...

  8. Spring Boot自动配置原理、实战

    Spring Boot自动配置原理 Spring Boot的自动配置注解是@EnableAutoConfiguration, 从上面的@Import的类可以找到下面自动加载自动配置的映射. org.s ...

  9. Spring Boot 自动装配(二)

    目录 目录 前言 1.起源 2.Spring Boot 自动装配实现 2.1.@EnableAutoConfiguration 实现 2.1.1. 获取默认包扫描路径 2.1.2.获取自动装配的组件 ...

随机推荐

  1. JavaScript DOM编程艺术-第一章

    发现基础不是很好,补习一下.37买了2本书(dom编程和高级程序设计). 以前读书总是自己勾勾画画,有点没意思.现在写下来,说不定会成为传世经典.哈哈...........随便扯扯淡. 第一天(201 ...

  2. http常见7种请求

    抛砖引玉,聊下概念性的东西先: HTTP协议 (Hyper Text Transfer Protocol) HTTP是一个基于TCP/IP通信协议来传递数据,包括html文件.图像.结果等,即是一个客 ...

  3. Cocos2d-x中使用的数据容器类

    |   版权声明:本文为博主原创文章,未经博主允许不得转载. 在计算机的数据结构中,有着数组,链表,堆栈,队列,树,图,哈希表等一些结构.在面向对象的语言中,这些结构被封装成了特定的类,而这些类就是容 ...

  4. Cocos2d-x之事件处理机制

    |   版权声明:本文为博主原创文章,未经博主允许不得转载. 事件处理机制分为单点触屏,多点触屏,加速度事件,键盘事件和鼠标事件.在现在的智能手机中,触屏的应用比较的广泛,尤其是多点触屏事件的技术,使 ...

  5. js的浏览器判断方法

    使用navigator.userAgent来判断浏览器类型. 1.浏览器版本号函数: var br=navigator.userAgent.toLowerCase();   var browserVe ...

  6. C++中函数模板的深入理解

    1,函数模板深入理解: 1,编译器从函数模板通过具体类型产生不同的函数: 1,模板就是模子,通过这个模子可以产生很多的实物: 2,函数模板就是编译器用来产生具体函数的模子: 2,编译器会对函数模板进行 ...

  7. terminal Failed to fork(connot allocate memory)问题处理

    今天遇到服务器无法SSH,VNC操作命令提示fork:cannot allocate memory free查看内存还有(注意,命令可能要多敲几次才会出来) 查看最大进程数 sysctl kernel ...

  8. Java中实现pdf在线查看和下载

    Java中实现PDF的在线查看和下载,可以以servlet来实现. /** * 支持在线打开和下载 * * @param filePath * @param response * @param isO ...

  9. bzoj2582 [Usaco2012Jan]Bovine Alliance

    [Usaco2012Jan]Bovine Alliance Time Limit: 2 Sec Memory Limit: 128 MB Description Bessie and her bovi ...

  10. 比较map的value

    Collection<CardInfo> values = splitCardInfo.getCardType().values();Iterator<CardInfo> it ...