环境
- 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 的版本:
1 | < dependencymanagement >< 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 > |
添加用到的依赖:
1 | < dependencies >< 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 >< dependency >< groupid >org.springframework.boot</ groupid >< artifactid >spring-boot-starter-test</ artifactid ></ dependency >< dependency >< groupid >org.springframework.cloud</ groupid >< artifactid >spring-cloud-starter-netflix-eureka-server</ artifactid ></ dependency ></ dependencies > |
配置文件
1 2 3 4 5 6 7 8 | 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 启动类
1 2 3 4 5 6 7 | @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
。 我们看看这个注解
1 2 3 4 5 6 | @Target (ElementType.TYPE) @Retention (RetentionPolicy.RUNTIME) @Documented @Import (EurekaServerMarkerConfiguration. class ) public @interface EnableEurekaServer { } |
上面有个@Import(EurekaServerMarkerConfiguration.class)
注解导入了EurekaServerMarkerConfiguration
配置类,我们看下配置类:
1 2 3 4 5 6 7 8 9 | @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
自动配置类里面都干了啥。
1 2 3 4 5 6 7 | @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
配置文件,这个没啥意思。
然后,看看里面成员有哪些。
1 2 3 4 5 6 7 8 9 10 | @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
1 2 3 4 5 | @Bean @ConditionalOnProperty (prefix = "eureka.dashboard" , name = "enabled" , matchIfMissing = true ) public EurekaController eurekaController() { return new EurekaController( this .applicationInfoManager); } |
注册表创建
1 2 3 4 5 6 7 8 9 | @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
类。
集群节点信息类对象
1 2 3 4 5 6 7 | @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 的ApplicationListene
r 事件监听接口,自然而然的RefreshablePeerEurekaNodes类具有了刷新集群节点信息功能(能力)。
EurekaServerContext
1 2 3 4 5 6 | @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 启动的时候会初始化PeerEurekaNodes
与PeerAwareInstanceRegistry
注册表,销毁的是否停止这2个组件
EurekaServerBootstrap
1 2 3 4 5 6 7 | @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 初始化用的。
1 2 3 4 | @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 方法干了啥
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | @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(); } |
创建了一个线程,先是执行eurekaServerBootstrap
的contextInitialized
初始化方法。接着就是发布 EurekaRegistryAvailableEvent
事件,设置running 为true ,最后就是发布EurekaServerStartedEvent
事件。 这里我们只关心eurekaServerBootstrap的contextInitialized
方法。
1 2 3 4 5 | public void contextInitialized(ServletContext context) { initEurekaEnvironment(); initEurekaServerContext(); context.setAttribute(EurekaServerContext. class .getName(), this .serverContext); } |
初始化eureka environment, 接着初始化context,最后是将context塞到 ServletContext的属性中。 initEurekaEnvironment这个我们就不看了。主要看下initEurekaServerContext 方法:
1 2 3 4 5 6 7 8 9 10 11 12 | 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);
这行代码没干啥。
1 2 | 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
方法
1 2 3 4 5 | @PostConstruct public void initialize() { this .peerEurekaNodes.start(); this .registry.init( this .peerEurekaNodes); } |
干了2件事,启动peerEurekaNodes
,初始化注册表。 peerEurekaNodes#start
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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分钟。
注册表初始化:
1 2 3 4 5 6 7 8 | @Override public void init(PeerEurekaNodes peerEurekaNodes) throws Exception { this .numberOfReplicationsLastMin.start(); this .peerEurekaNodes = peerEurekaNodes; initializedResponseCache(); scheduleRenewalThresholdUpdateTask(); initRemoteRegionRegistry(); } |
-
numberOfReplicationsLastMin
这是记录续约次数的一个组件,用在服务剔除。 -
initializedResponseCache
初始化响应cache ,这个其实就是 服务发现的时候三级缓存。
参考
springcloud-source-study学习github地址
以上就是Eureka源码阅读解析Server服务端启动流程实例的详细内容,更多关于Eureka Server服务端启动流程的资料请关注IT俱乐部其它相关文章!