当前位置:   article > 正文

SpringCloud Eureka Server源码解析(启动流程)_springcloud eureka源码 idea启动

springcloud eureka源码 idea启动

原创不易,转载请注明出处


前言

本文主要看看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项目

我这边spring boot 版本是2.1.6.RELEASE(比较老)

1.2 pom.xml文件添加
<dependencyManagement>
    <!--引入springcloud依赖的-->
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Greenwich.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

用来规范spring cloud 的版本

<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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

添加用到的依赖

1.3 配置文件
eureka:
  instance:
    hostname: localhost
  client:
    service-url:   #  eureka server 的地址, 咱们单实例模式就写自己好了
      defaultZone:  http://localhost:9090/eureka
    register-with-eureka: false  # 不向eureka server 注册自己
    fetch-registry: false  # 不向eureka server 获取服务列表
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
1.4 启动类
@SpringBootApplication
@EnableEurekaServer
public class SpringCloudEurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringCloudEurekaServerApplication.class, args);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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

1.5 启动

在这里插入图片描述
注意:由于是源码解析的文章,更详细的配置可以查看《SpringCloud之Eureka使用篇

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 {
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

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

@Configuration
public class EurekaServerMarkerConfiguration {
	@Bean
	public Marker eurekaServerMarkerBean() {
		return new Marker();
	}
	class Marker {
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

就是创建了一个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{}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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

  1. @Import(EurekaServerInitializerConfiguration.class) : 导入(装配)配置类EurekaServerInitializerConfiguration,这个我们后面看下,属于初始化流程。
  2. @ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class) 就是是否存在EurekaServerMarkerConfiguration.Marker 类的bean实例,这个肯定存在的,我们在@EnableEurekaServer 注解中就创建了这么一个bean 交给spring 管理了。存在就会往下走,不存在就拉倒了,不会再加载配置类里面别的东西了,也就是不会自动启动eureka server了。
  3. @EnableConfigurationProperties({ EurekaDashboardProperties.class,
    InstanceRegistryProperties.class }) 这个就是装配这两个配置类,一个是关于Dashboard 的,一个是关于instance 的配置,也就是eureka server的配置, 就是将我们写在application.yml配置文件中关于eureka 的配置set到这里面的属性中。
  4. @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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

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 注解也是可以的。

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

  1. dashboard 的controller
@Bean
@ConditionalOnProperty(prefix = "eureka.dashboard", name = "enabled", matchIfMissing = true)
public EurekaController eurekaController() {
return new EurekaController(this.applicationInfoManager);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  1. 注册表创建
@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());
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

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

  1. 集群节点信息类对象
@Bean
@ConditionalOnMissingBean
public PeerEurekaNodes peerEurekaNodes(PeerAwareInstanceRegistry registry,
		ServerCodecs serverCodecs) {
	return new RefreshablePeerEurekaNodes(registry, this.eurekaServerConfig,
			this.eurekaClientConfig, serverCodecs, this.applicationInfoManager);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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

@Bean
public EurekaServerContext eurekaServerContext(ServerCodecs serverCodecs,
		PeerAwareInstanceRegistry registry, PeerEurekaNodes peerEurekaNodes) {
	return new DefaultEurekaServerContext(this.eurekaServerConfig, serverCodecs,
			registry, peerEurekaNodes, this.applicationInfoManager);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

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

@Bean
public EurekaServerBootstrap eurekaServerBootstrap(PeerAwareInstanceRegistry registry,
		EurekaServerContext serverContext) {
	return new EurekaServerBootstrap(this.applicationInfoManager,
			this.eurekaClientConfig, this.eurekaServerConfig, registry,
			serverContext);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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

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

3.eureka server 初始化源码解析

3.1 EurekaServerInitializerConfiguration

第二节介绍 spring cloud eureka server 启动的时候自动装配的一些组件,本小节就看下eureka server的初始化流程
在自动装配类EurekaServerAutoConfiguration 类上面声明了@Import(EurekaServerInitializerConfiguration.class) ,我们介绍说是导入(加载)EurekaServerInitializerConfiguration 这个配置,一看这个类名字就是eureka server 初始化用的。

@Configuration
public class EurekaServerInitializerConfiguration
		implements ServletContextAware, SmartLifecycle, Ordered {
  • 1
  • 2
  • 3

@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();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

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

public void contextInitialized(ServletContext context) {
	initEurekaEnvironment();
	initEurekaServerContext();
	context.setAttribute(EurekaServerContext.class.getName(), this.serverContext);
}
  • 1
  • 2
  • 3
  • 4
  • 5

初始化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();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

isAws 是亚马逊云环境的时候执行if里面的那一堆,这个不看了。
EurekaServerContextHolder.initialize(this.serverContext);这行代码没干啥。

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

这个就是去集群中的其他节点拉取注册表。

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);
}
  • 1
  • 2
  • 3
  • 4
  • 5

干了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
     );
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

先是更新集群节点信息,就是创建节点对象。
接着就是创建一个定时任务更新,默认是10分钟。

注册表初始化:

@Override
public void init(PeerEurekaNodes peerEurekaNodes) throws Exception {
    this.numberOfReplicationsLastMin.start();
    this.peerEurekaNodes = peerEurekaNodes;
    initializedResponseCache();
    scheduleRenewalThresholdUpdateTask();
    initRemoteRegionRegistry();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

numberOfReplicationsLastMin 这是记录续约次数的一个组件,用在服务剔除。
initializedResponseCache 初始化响应cache ,这个其实就是 服务发现的时候三级缓存。

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号