环境

  • eureka版本:1.10.11
  • Spring Cloud : 2020.0.2
  • Spring Boot :2.4.4
    测试demo代码:github.com/hsfxuebao/s…

本文主要看看spring cloud是怎样自动装配eureka server 并启动eureka server的并解析其关键源码。首先我们会配置启动一个spring cloud eureka server 服务,接着看看是spring cloud怎样自动装配eureka的,并看看一些核心组件的创建源码,最后解析下eureka server 启动初始化流程,看看都干了些啥东西

1.spring cloud整合eureka server demo

1.1 新建spring boot项目

pom.xml文件添加

用来规范spring cloud 的版本:

<dependencyManagement>
    <!--引入springcloud依赖的-->
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>2020.0.2E</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

添加用到的依赖:

<dependencies>
    <!--web依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-commons</artifactId>
    </dependency>
    <!--unit test-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
    <!--spring cloud eureka server 依赖-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
</dependencies>

配置文件

eureka:
  instance:
    hostname: localhost
  client:
    service-url:   #  eureka server 的地址, 咱们单实例模式就写自己好了
      defaultZone:  http://localhost:7000/eureka
    register-with-eureka: false  # 不向eureka server 注册自己
    fetch-registry: false  # 不向eureka server 获取服务列表

1.2 启动类

@SpringBootApplication
@EnableEurekaServer
public class EurekaServer {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServer.class, args);
    }
}

添加@EnableEurekaServer注解,表示它是个eureka server

1.3 启动

访问地址:http://localhost:7000/

注意:由于是源码解析的文章,更详细的配置可以查看github.com/hsfxuebao/s…

2. spring cloud自动装配eureka server源码解析

2.1 @EnableEurekaServer注解

上一节配置eureka server的时候我们在配置类上加了个@EnableEurekaServer注解,表示启动一个eureka server 。 我们看看这个注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(EurekaServerMarkerConfiguration.class)
public @interface EnableEurekaServer {
}

上面有个@Import(EurekaServerMarkerConfiguration.class) 注解导入了EurekaServerMarkerConfiguration配置类,我们看下配置类:

@Configuration
public class EurekaServerMarkerConfiguration {
	@Bean
	public Marker eurekaServerMarkerBean() {
		return new Marker();
	}
	class Marker {
	}
}

就是创建了一个EurekaServerMarkerConfiguration.Marker 对象,交给spring保管,一看就是个标记,标识,仅仅是个标识。

2.2 EurekaServerAutoConfiguration

2.2.1 查找starter 自动装配类的技巧

spring boot的starter基本都会自动装配类,也就是AutoConfiguration 结尾的类,如果我们找不到某个starter的自动装配类是那个,可以去starter对应jar 包里面META-INF 文件夹下面找spring.factories (这是spring spi 配置文件)文件。比如说我可以在spring-cloud-netflix-eureka-server 这个项目下找到META-INF 文件夹下面找spring.factories文件。

文件内容就是上图里面的,可以看到自动装配类就是EurekaServerAutoConfiguration

2.2.2 EurekaServerAutoConfiguration源码解析

首先,看看 EurekaServerAutoConfiguration 自动配置类里面都干了啥。

@Configuration
@Import(EurekaServerInitializerConfiguration.class)
@ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class)
@EnableConfigurationProperties({ EurekaDashboardProperties.class,
		InstanceRegistryProperties.class })
@PropertySource("classpath:/eureka/server.properties")
public class EurekaServerAutoConfiguration extends WebMvcConfigurerAdapter{}

先看看类上面声明的这一堆注解:

  • @Import(EurekaServerInitializerConfiguration.class) : 导入(装配)配置类EurekaServerInitializerConfiguration,这个我们后面看下,属于初始化流程。
  • @ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class) 就是是否存在EurekaServerMarkerConfiguration.Marker 类的bean实例,这个肯定存在的,我们在@EnableEurekaServer 注解中就创建了这么一个bean 交给spring 管理了。存在就会往下走,不存在就拉倒了,不会再加载配置类里面别的东西了,也就是不会自动启动eureka server了。
  •  @EnableConfigurationProperties({ EurekaDashboardProperties.class, InstanceRegistryProperties.class }) 这个就是装配这两个配置类,一个是关于Dashboard 的,一个是关于instance 的配置,也就是eureka server的配置, 就是将我们写在application.yml配置文件中关于eureka 的配置set到这里面的属性中。
  • @PropertySource(“classpath:/eureka/server.properties”) 加载/eureka/server.properties 配置文件,这个没啥意思。

然后,看看里面成员有哪些。

@Autowired
private ApplicationInfoManager applicationInfoManager;
@Autowired
private EurekaServerConfig eurekaServerConfig;
@Autowired
private EurekaClientConfig eurekaClientConfig;
@Autowired
private EurekaClient eurekaClient;
@Autowired
private InstanceRegistryProperties instanceRegistryProperties;

ApplicationInfoManager / EurekaClientConfig / EurekaClient 这几个bean 一看就是eureka client 里面的,我们这里是eureka server ,为啥能够注入进来呢?

  • 原因是 eureka server 的starter 里面依赖了eureka client starter,eureka client starter自动装配的这些实例bean 。有些小伙伴可能会有疑问,我启用(自动装配)eureka client,不需要在配置类上面添加@EnableEurekaClient注解嘛。其实从spring cloud netflix 1.4版本往后主要引入了这个 eureka client starter 依赖,就会自动装配,不需要添加@EnableEurekaClient 注解也是可以的。

接着,看看创建了哪些核心组件

dashboard 的controller

@Bean
@ConditionalOnProperty(prefix = "eureka.dashboard", name = "enabled", matchIfMissing = true)
public EurekaController eurekaController() {
return new EurekaController(this.applicationInfoManager);
}

注册表创建

@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());
}

注册表,就是存放我们注册的实例信息的,这个是个非常核心的组件。这里直接创建了一个InstanceRegistry 对象,这个InstanceRegistry继承eureka server 里面PeerAwareInstanceRegistryImpl 类。

集群节点信息类对象

@Bean
@ConditionalOnMissingBean
public PeerEurekaNodes peerEurekaNodes(PeerAwareInstanceRegistry registry,
                ServerCodecs serverCodecs) {
        return new RefreshablePeerEurekaNodes(registry, this.eurekaServerConfig,
                        this.eurekaClientConfig, serverCodecs, this.applicationInfoManager);
}

PeerEurekaNodes 这个类,从名字上也能看出来是集群节点的类,而且是Nodes ,表示多个节点,其实里面就是封装eureka server 集群的节点们。这里是创建RefreshablePeerEurekaNodes 对象,RefreshablePeerEurekaNodes继承PeerEurekaNodes 类,实现spring 的ApplicationListener 事件监听接口,自然而然的RefreshablePeerEurekaNodes类具有了刷新集群节点信息功能(能力)。

EurekaServerContext

@Bean
public EurekaServerContext eurekaServerContext(ServerCodecs serverCodecs,
                PeerAwareInstanceRegistry registry, PeerEurekaNodes peerEurekaNodes) {
        return new DefaultEurekaServerContext(this.eurekaServerConfig, serverCodecs,
                        registry, peerEurekaNodes, this.applicationInfoManager);
}

EurekaServerContext 从字面上是eureka server 上下文,其实就是eureka server 启动的时候会初始化PeerEurekaNodesPeerAwareInstanceRegistry 注册表,销毁的是否停止这2个组件

EurekaServerBootstrap

@Bean
public EurekaServerBootstrap eurekaServerBootstrap(PeerAwareInstanceRegistry registry,
                EurekaServerContext serverContext) {
        return new EurekaServerBootstrap(this.applicationInfoManager,
                        this.eurekaClientConfig, this.eurekaServerConfig, registry,
                        serverContext);
}

一般叫Bootstrap 的类都是那种掌管项目启动与停止的,EurekaServerBootstrap 也不例外,它里面就有contextInitialized 项目启动与contextDestroyed项目停止/销毁的方法。

jersey框架 关于jersey框架的东西,eureka server 对外暴露rest ful接口,使用的框架就是jersey(这玩意国内很少用),作用/定位就跟我们常用的springmvc 框架差不多。

3. eureka server 初始化源码解析

3.1 EurekaServerInitializerConfiguration

第2小节介绍 spring cloud eureka server 启动的时候自动装配的一些组件,本小节就看下eureka server的初始化流程。

在自动装配类EurekaServerAutoConfiguration 类上面声明了@Import(EurekaServerInitializerConfiguration.class) ,我们介绍说是导入(加载)EurekaServerInitializerConfiguration 这个配置,一看这个类名字就是eureka server 初始化用的。

@Configuration
public class EurekaServerInitializerConfiguration
		implements ServletContextAware, SmartLifecycle, Ordered {
}

@Configuration是个配置类,实现ServletContextAware,SmartLifecycle,Ordered 接口:

  • ServletContextAware 作用是自动注入ServletContext 实例。
  • SmartLifecycle接口 属于spring 声明周期的,start 方法执行时机是,当spring 的bean都实例化,初始化完事后,会调用SmartLifecycle 的start方法,isAutoStartup 方法返回的true 或者false 决定要不要执行start方法,这里isAutoStartup方法返回的true。
  • stop 方法就是项目停止,容器销毁的时候会调用。

先来看下start 方法干了啥

@Override
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();
}

创建了一个线程,先是执行eurekaServerBootstrapcontextInitialized 初始化方法。接着就是发布 EurekaRegistryAvailableEvent 事件,设置running 为true ,最后就是发布EurekaServerStartedEvent 事件。 这里我们只关心eurekaServerBootstrap的contextInitialized 方法。

public void contextInitialized(ServletContext context) {
	initEurekaEnvironment();
	initEurekaServerContext();
	context.setAttribute(EurekaServerContext.class.getName(), this.serverContext);
}

初始化eureka environment, 接着初始化context,最后是将context塞到 ServletContext的属性中。 initEurekaEnvironment这个我们就不看了。主要看下initEurekaServerContext 方法:

if (isAws(this.applicationInfoManager.getInfo())) {
	this.awsBinder = new AwsBinderDelegate(this.eurekaServerConfig,
			this.eurekaClientConfig, this.registry, this.applicationInfoManager);
	this.awsBinder.start();
}
EurekaServerContextHolder.initialize(this.serverContext);
log.info("Initialized server context");
// Copy registry from neighboring eureka node
int registryCount = this.registry.syncUp();
this.registry.openForTraffic(this.applicationInfoManager, registryCount);
// Register all monitoring statistics.
EurekaMonitors.registerAllStats();

isAws 是亚马逊云环境的时候执行if里面的那一堆,这个不看了。

EurekaServerContextHolder.initialize(this.serverContext);这行代码没干啥。

int registryCount = this.registry.syncUp();
this.registry.openForTraffic(this.applicationInfoManager, registryCount);

registry.syncUp()这个就是去集群中的其他节点拉取注册表。下篇文章分析 registry.openForTraffic()这个是Server端定时清理过期的Client。以后在详细分析。

3.2 DefaultEurekaServerContext

我们在介绍自动装配类EurekaServerAutoConfiguration 装配组件的时候,介绍过EurekaServerContext ,说他字面上是eureka server 上下文,其实就是eureka server 启动的时候会初始化PeerEurekaNodes 与PeerAwareInstanceRegistry 注册表,销毁的是否停止这2个组件 我们来看下 @PostConstruct 注解修饰的initialize 方法

@PostConstruct
public void initialize() {
    this.peerEurekaNodes.start();
    this.registry.init(this.peerEurekaNodes);
}

干了2件事,启动peerEurekaNodes ,初始化注册表。 peerEurekaNodes#start:

public void start() {
     updatePeerEurekaNodes(resolvePeerUrls());
     Runnable peersUpdateTask = new Runnable() {
         @Override
         public void run() {
             updatePeerEurekaNodes(resolvePeerUrls());
         }
     };
     taskExecutor.scheduleWithFixedDelay(
             peersUpdateTask,
             serverConfig.getPeerEurekaNodesUpdateIntervalMs(),
             serverConfig.getPeerEurekaNodesUpdateIntervalMs(),
             TimeUnit.MILLISECONDS
     );
}

先是更新集群节点信息,就是创建节点对象。

接着就是创建一个定时任务更新,默认是10分钟。

注册表初始化:

@Override
public void init(PeerEurekaNodes peerEurekaNodes) throws Exception {
    this.numberOfReplicationsLastMin.start();
    this.peerEurekaNodes = peerEurekaNodes;
    initializedResponseCache();
    scheduleRenewalThresholdUpdateTask();
    initRemoteRegionRegistry();
}
  • numberOfReplicationsLastMin 这是记录续约次数的一个组件,用在服务剔除。
  • initializedResponseCache 初始化响应cache ,这个其实就是 服务发现的时候三级缓存。

参考

eureka-0.10.11源码(注释)

springcloud-source-study学习github地址

以上就是Eureka源码阅读解析Server服务端启动流程实例的详细内容,更多关于Eureka Server服务端启动流程的资料请关注Devmax其它相关文章!

Eureka源码阅读解析Server服务端启动流程实例的更多相关文章

  1. ios – Swift Eureka Form中的循环

    我正在构建一个Eureka表单,并希望在表单中放置一个循环来构建基于数组的步进器列表.我试图使用的代码是:但是,当我这样做时,我在StepperRow行上出现了一个错误:所以看起来Swift不再认为它在形式之内并且正在关注

  2. [快速学会Swift第三方库] Eureka篇

    [快速学会Swift第三方库]Eureka篇Eureka可以帮你简单优雅的实现动态table-view表单。目录快速学会Swift第三方库Eureka篇目录编码之前导入Eureka其他操作创建表单基础表单选择类型表单Segment风格选择器标准选择器pickerView风格选择器三种风格选择器效果对比带输入框的表单自定义Row深入学习编码之前导入Eureka推荐使用CocoaPods进行导入,CocoaPods是一个负责管理iOS项目中第三方开源库的工具,安装CocoaPods之后使用命令行就能轻松地对所

  3. PHP6连接SQLServer2005的三部曲

    PHP6怎么连接sqlserver2005呢?其实方法步骤很简单的。下面脚本之家小编给大家介绍PHP6连接SQLServer2005的三部曲,感兴趣的朋友参考下吧

  4. React服务端渲染和同构的实现

    本文主要介绍了React服务端渲染和同构的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  5. Framework源码面试之activity启动流程

    这篇文章主要为大家介绍了Framework源码面试之activity启动流程实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  6. 服务端nodejs抓取jsonp接口数据实现示例

    这篇文章主要为大家介绍了服务端nodejs抓取jsonp接口数据实现示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  7. Java Eureka探究细枝末节

    Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的

  8. Spring Cloud详细讲解zuul集成Eureka流程

    这篇文章主要介绍了Spring Cloud zuul集成Eureka,Eureka Client中内置一个负载均衡器,用来进行基本的负载均衡,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  9. 一文带你看懂Android Application启动流程是怎样的

    谈到Android Application的启动流程,很多文章都是各种源码类和方法的一堆调用关系,这样的文章就算看一百遍,也只是云里雾里。源码得看,但是最好不要一下子深陷到源码的细节之中,不可自拔。这里站在前人的基础之上做一个总结

  10. List the Stored Procedures in a SQL Server database

    ListtheStoredProceduresinaSQLServerdatabase.SupportedPlatformsSQLServer2000YesScriptCodestrDBServerName="."strDBName="Northwind"SetobjSQLServer=CreateObject("SQLDMO.SQLServer")objSQLServer.LoginSecure

随机推荐

  1. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  2. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  3. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  4. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  5. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  6. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  7. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  8. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  9. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. Spring JdbcTemplate执行数据库操作详解

    JdbcTemplate是Spring框架自带的对JDBC操作的封装,目的是提供统一的模板方法使对数据库的操作更加方便、友好,效率也不错,这篇文章主要介绍了Spring JdbcTemplate执行数据库操作,需要的朋友可以参考下

返回
顶部