微服务笔记之Euraka(2)
Eureka Server启动过程
- 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)的更多相关文章
- Spring Cloud微服务笔记(二)Spring Cloud 简介
Spring Cloud 简介 Spring Cloud的设计理念是Integrate Everything,即充分利用现有的开源组件, 在它们之上设计一套统一的规范/接口使它们能够接入Spring ...
- Spring Cloud微服务笔记(三)服务治理:Spring Cloud Eureka快速入门
服务治理:Spring Cloud Eureka 一.服务治理 服务治理是微服务架构中最为核心和基础的模块,它主要用来实现各个微服务实例的自动化注册与发现. 1.服务注册: 在服务治理框架中,通常会构 ...
- Spring Cloud微服务笔记(一)微服务概念
微服务概念 一.什么是微服务架构 微服务,是一个小的.松耦合的分布式服务. 为什么需要微服务: 1)单体系统部署在一个进程中,修改了一个小功能,为了部署上线就会影响其他功能. 2)单体应用各个功能模块 ...
- SpringCloud微服务笔记-Nginx实现网关反向代理
背景 当前在SpringCloud微服务架构下,网关作为服务的入口尤为重要,一旦网关发生单点故障会导致整个服务集群瘫痪,为了保证网关的高可用可以通过Nginx的反向代理功能实现网关的高可用. 项目源码 ...
- Spring Cloud 微服务笔记(七) Zuul入门
Zuul入门 Zuul是从设备和网站到后端应用程序所有请求的前门,为内部服务提供可配置的对外URL到服务的 映射关系,基于JVM的后端路由器.其具备一下功能: 1)认证与授权 2)压力控制 3)金丝雀 ...
- Spring Cloud 微服务笔记(六)Spring Cloud Hystrix
Spring Cloud Hystrix Hystrix是一个延迟和容错库,旨在隔离远程系统.服务和第三方库,阻止链接故障,在复杂的分布式系统中实现恢复能力. 一.快速入门 1)依赖: <dep ...
- Spring Cloud微服务笔记(五)Feign
Feign 一.Feign概述 Feign是一个声明式的Web Service客户端.在Spring Cloud 中使用Feign,可以做到 使用HTTP请求访问远程服务,就像调用本地方法一样,同时它 ...
- Spring Cloud微服务笔记(四)客户端负载均衡:Spring Cloud Ribbon
客户端负载均衡:Spring Cloud Ribbon 一.负载均衡概念 负载均衡在系统架构中是一个非常重要,并且是不得不去实施的内容.因为负载均衡对系统的高可用性. 网络压力的缓解和处理能力的扩容的 ...
- 将微服务注册到Euraka
1.添加依赖 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId> ...
- 一起学习 微服务(MicroServices)-笔记
笔记 微服务特性: 1. 小 专注与做一件事(适合团队就是最好的) 2. 松耦合 独立部署 3. 进程独立 4. 轻量级通信机制 实践: 1. 微服务周边的一系列基础建设 Load Balancing ...
随机推荐
- IntelliJ中高效重构的 10 个快捷方式
前言 在日常的开发工作中,我们经常需要重构,重构可以让我们写出的代码更上一层楼.所以,我会借助IntelliJ提供的一些功能,帮助我高效进行重构.这里是我推荐10个快捷方式,也是我每天都在使用的,非常 ...
- Java入门与进阶 P-3.5+P-3.6
计数循环 这个循环需要执行多少次? 循环停下来的时候,有没有输出到最后的0 ? 循环结束后count的值是多少 算数平方 让用户输入一系列的正整数,最后输入-1标识输入结束,然后程序计算出这些数字的平 ...
- 笔记本USB接口案例_分析-笔记本USB接口案例_实现
笔记本USB接口案例_分析 笔记本电脑(laptop)通常具备使用USB设备的功能.在生产时,笔记本都预留了可以插入USB设备的USB接口, 但具体是什么USB设备,笔记本厂商并不关心,只要符合USB ...
- 计算机网络基础07 DNS概述
1 什么是DNS Domain Name System(域名系统),它是一个应用层的服务.它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网.当前,对于每一级域名长度的限制是 ...
- Solon2 开发之插件,二、插件扩展机制(Spi)
插件扩展机制,是基于 "插件" + "配置申明" 实现的解耦的扩展机制(类似 Spring Factories.Java Spi):简单.弹性.自由.它的核心作 ...
- .net core 删除指定路径下的所有文件以及文件夹(文件夹建议保留目录)
1.服务层 /// <summary> /// 删除指定路径下的所有文件 /// </summary> /// <param name="filepath&qu ...
- 剑指 Offer 34. 二叉树中和为某一值的路径(java解题)
目录 1. 题目 2. 解题思路 3. 数据类型功能函数总结 4. java代码 1. 题目 给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总 ...
- javaEE(单元测试、反射、动态代理、xml)
单元测试 最小的功能单元编写测试代码,java针对方法,检查方法的正确性 JUnit单元测试框架 @Test注解 public class A { @Test public void a(){ ... ...
- 安卓逆向 crmak的动态调试
1.java代码分析 检测是否输入密码,输入了就进行对比 由此,我们需要进入SO进行动态调试了 2.SO调试 过程太复杂,凌晨才搞出来,就直接给答案了,有文件检测和端口检测 还有调试检测,都需要干掉
- Winform程序制作安装包
记录一下Winform程序打包过程 参考文章:VS2017 WinFrom打包设置与教程 下载 Visual Studio Installer 拓展插件 从VS2017开始VS已默认不再集成Insta ...