文章目录
前言
我们按照如下流程去看eureka server源码
自动配置 -> server启动 -> 初始化上下文 -> 创建服务注册表 -> 心跳监控
1.自动配置类-EurekaServerAutoConfiguration
这个类里面,主要了三件事
- 1 加载对外提供eruka信息的的接口
- 2 初始化集群注册表
- 3 配置节点信息-双节点成集群
- 4 上下文
- 5 启动server
- 6 配置拦截器
@Configuration
@Import(EurekaServerInitializerConfiguration.class)
@ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class)
@EnableConfigurationProperties({ EurekaDashboardProperties.class,
InstanceRegistryProperties.class })
@PropertySource("classpath:/eureka/server.properties")
public class EurekaServerAutoConfiguration extends WebMvcConfigurerAdapter {
// 加载EurekaController(下面会讲), 用来获取eurekaServer的信息
@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.getExpectedNumberOfRenewsPerMin(),
this.instanceRegistryProperties.getDefaultOpenForTrafficCount());
}
// 配置服务节点信息,这里的作用主要是为了配置Eureka的peer节点,也就是说当有收到有节点注册上来
//的时候,需要通知给那些服务节点, (互为一个集群)
@Bean
@ConditionalOnMissingBean
public PeerEurekaNodes peerEurekaNodes(PeerAwareInstanceRegistry registry,
ServerCodecs serverCodecs) {
return new PeerEurekaNodes(registry, this.eurekaServerConfig,
this.eurekaClientConfig, serverCodecs, this.applicationInfoManager);
}
// EurekaServer的上下文
@Bean
public EurekaServerContext eurekaServerContext(ServerCodecs serverCodecs,PeerAwareInstanceRegistry registry, PeerEurekaNodes peerEurekaNodes) {
return new DefaultEurekaServerContext(this.eurekaServerConfig, serverCodecs,
registry, peerEurekaNodes, this.applicationInfoManager);
}
// 这个类的作用是spring‐cloud和原生eureka的胶水代码,通过这个类来启动EurekaSever
// 后面这个类会在EurekaServerInitializerConfiguration被调用,进行eureka启动
@Bean
public EurekaServerBootstrap eurekaServerBootstrap(PeerAwareInstanceRegistry registry,EurekaServerContext serverContext) {
return new EurekaServerBootstrap(this.applicationInfoManager,
this.eurekaClientConfig, this.eurekaServerConfig, registry,
serverContext);
}
// 配置拦截器,通过他来实现eurekaServer对外的restFull接口
@Bean
public FilterRegistrationBean jerseyFilterRegistration(Application eurekaJerseyApp) {
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new ServletContainer(eurekaJerseyApp));
bean.setOrder(2147483647);
bean.setUrlPatterns(Collections.singletonList("/eureka/*"));
return bean;
}
EurekaControoler 解析
EurekaControoler.class 这个类很好理解,字面意思即功能,开放出一个rest接口
定义
@Controller
@RequestMapping({"${eureka.dashboard.path:/}"})
public class EurekaController {
@Value("${eureka.dashboard.path:/}")
private String dashboardPath = "";
private ApplicationInfoManager applicationInfoManager;
public EurekaController(ApplicationInfoManager applicationInfoManager) {
this.applicationInfoManager = applicationInfoManager;
}
}
方法
观察看 这个方法
public String status(HttpServletRequest request, Map<String, Object> model) {
this.populateBase(request, model);
this.populateApps(model);
StatusInfo statusInfo;
try {
statusInfo = (new StatusResource()).getStatusInfo();
} catch (Exception var5) {
statusInfo = Builder.newBuilder().isHealthy(false).build();
}
model.put("statusInfo", statusInfo);
this.populateInstanceInfo(model, statusInfo);
this.filterReplicas(model, statusInfo);
return "eureka/status";
}
我们点进去 populateInstanceInfo()
private void populateInstanceInfo(Map<String, Object> model, StatusInfo statusInfo) {
InstanceInfo instanceInfo = statusInfo.getInstanceInfo();
Map<String, String> instanceMap = new HashMap();
instanceMap.put("ipAddr", instanceInfo.getIPAddr());
instanceMap.put("status", instanceInfo.getStatus().toString());
if (instanceInfo.getDataCenterInfo().getName() == Name.Amazon) {
AmazonInfo info = (AmazonInfo)instanceInfo.getDataCenterInfo();
instanceMap.put("availability-zone", info.get(MetaDataKey.availabilityZone));
instanceMap.put("public-ipv4", info.get(MetaDataKey.publicIpv4));
instanceMap.put("instance-id", info.get(MetaDataKey.instanceId));
instanceMap.put("public-hostname", info.get(MetaDataKey.publicHostname));
instanceMap.put("ami-id", info.get(MetaDataKey.amiId));
instanceMap.put("instance-type", info.get(MetaDataKey.instanceType));
}
model.put("instanceInfo", instanceMap);
}
在这个里面,可以看到instanceMap
这个字段,里面看到了instance-id
,instance-type
就是存储的实例信息,也就是说,每次启动的时候,都会走这个方法,去把当前节点给注册进去(除了设置不注册自己)
EurekaServerInitializerConfiguration 解析
EurekaServerAutoConfiguration
这个类,他引入(import)
了这个EurekaServerInitializerConfiguration
类
我们点进去看看里面都有啥
怎么看就是这个start()
有点特殊,我们点开方法看看
public void start() {
// 这里启动了一个线程
(new Thread(new Runnable() {
public void run() {
try {
//初始化EurekaServer,同时启动Eureka Server
EurekaServerInitializerConfiguration.this.eurekaServerBootstrap.contextInitialized(EurekaServerInitializerConfiguration.this.servletContext);
// 日志 不管
EurekaServerInitializerConfiguration.log.info("Started Eureka Server");
// 发布EurekaServer的注册事件
EurekaServerInitializerConfiguration.this.publish(new EurekaRegistryAvailableEvent(EurekaServerInitializerConfiguration.this.getEurekaServerConfig()));
// 设置启动的状态为true
EurekaServerInitializerConfiguration.this.running = true;
// 发送Eureka Start 事件 , 其他还有各种事件,我们可以监听这种时间,然后做一些特定的业务需求
EurekaServerInitializerConfiguration.this.publish(new EurekaServerStartedEvent(EurekaServerInitializerConfiguration.this.getEurekaServerConfig()));
} catch (Exception var2) {
EurekaServerInitializerConfiguration.log.error("Could not initialize Eureka servlet context", var2);
}
}
})).start();
}
到了这一步,各项配置和参数准备好了,就差启动了!下面看这个类
EurekaServerBootstrap 解析
依旧在 EurekaServerAutoConfiguration
中,存在这么一个方法
@Bean
public EurekaServerBootstrap eurekaServerBootstrap(PeerAwareInstanceRegistry registry, EurekaServerContext serverContext) {
return new EurekaServerBootstrap(this.applicationInfoManager, this.eurekaClientConfig, this.eurekaServerConfig, registry, serverContext);
}
废话少说,跟进去
我们先看下这个方法 contextInitialize
contextInitialize() 解析
里面并没有什么东西,就是调自身的两个方法
先看第一个 initEurekaEnvironmen()
initEurekaEnvironmen() 解析
这个方法里面,设置了服务实例的的相关属性,字面意思是数据中心和环境,默认是test
环境
initEurekaServerContext() 解析
这个方法很关键,是在这个方法里面,去初始化eureka server的上下文的
protected void initEurekaServerContext() throws Exception {
JsonXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(), 10000);
XmlXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(), 10000);
if (this.isAws(this.applicationInfoManager.getInfo())) {
this.awsBinder = new AwsBinderDelegate(this.eurekaServerConfig, this.eurekaClientConfig, this.registry, this.applicationInfoManager);
this.awsBinder.start();
}
// 初始化eureka server上下文
EurekaServerContextHolder.initialize(this.serverContext);
log.info("Initialized server context");
// 从相邻的eureka节点复制注册表
int registryCount = this.registry.syncUp();
// 默认每30秒发送心跳,1分钟就是2次
// 修改eureka状态为up
// 同时,这里面会开启一个定时任务,用于清理60秒没有心跳的客户端。自动下线
this.registry.openForTraffic(this.applicationInfoManager, registryCount);
EurekaMonitors.registerAllStats();
}
这个方法里面,有一个syncUp()
方法,这个方法有什么用呢?
syncUp() 解析
这个方法,就是开始把其他服务往自己身上循环
注册
字面意思是 同步启动
,看下到底是有什么作用
public int syncUp() {
int count = 0;
for(int i = 0; i < this.serverConfig.getRegistrySyncRetries() && count == 0; ++i) {
if (i > 0) {
try {
Thread.sleep(this.serverConfig.getRegistrySyncRetryWaitMs());
} catch (InterruptedException var10) {
logger.warn("Interrupted during registry transfer..");
break;
}
}
Applications apps = this.eurekaClient.getApplications();
Iterator var4 = apps.getRegisteredApplications().iterator();
while(var4.hasNext()) {
Application app = (Application)var4.next();
// 获取服务实例列表 -> 这一步就是client往server上注册啦
Iterator var6 = app.getInstances().iterator();
while(var6.hasNext()) {
InstanceInfo instance = (InstanceInfo)var6.next();
try {
if (this.isRegisterable(instance)) {
// 将其他节点的实例注册到本节点
this.register(instance, instance.getLeaseInfo().getDurationInSecs(), true);
++count;
}
} catch (Throwable var9) {
logger.error("During DS init copy", var9);
}
}
}
}
return count;
}
server端快解析完了,可是我不想写了,明天再写!~ 累…