一.Eureka源码分析-Eureka的核心类:
1.InstanceInfo.java(主要的记录实例的基础信息com.netflix.appinfo.InstanceInfo.java)
2.LeaseInfo.java(记录服务实例的租约信息com.netflix.appinfo.LeaseInfo.java)
3.LeaseManager.java(定义服务中心的一般操作接口com.netflix.eureka.lease.LeaseManager.java)
public interface LeaseManager<T> {
//注册方法
void register(T var1, int var2, boolean var3);
//删除服务方法
boolean cancel(String var1, String var2, boolean var3);
//服务发送心跳
boolean renew(String var1, String var2, boolean var3);
//剔除租约到期的方法(委托一个定时器时间定时在执行)
void evict();
}
LeaseManager主要的实现类是:PeerAwareInstanceRegistryImpl.java
4.LookupService.java(定义client从服务端获取信息的接口方法 com.netflix.discovery.shared.LookupService.java)
public interface LookupService<T> {
//通过实例的appName去获取服务实例 Application.java中含有InstanceInfo的信息
Application getApplication(String var1);
通过所有的注册服务实例
Applications getApplications();
//通过appName(有些称为appId)去获取一个服务实例
List<InstanceInfo> getInstancesById(String var1);
//var1 传入的是virtuaHostname去获取下一个服务实例
InstanceInfo getNextServerFromEureka(String var1, boolean var2);
}
LookupService的实现类主要是:DiscoveryClient.java
比较重要的方法如下看名称就知道是干什么的啦,就不一一标注了:
二.封装源码api
方式一:自己写接口,通过restTemplate client 去掉用Eureka提供的官方api(自行百度),需要返回json请在请求头中加上Accept 字段.
方式二:因为源码中有部分的方法是受保护或私有的,根据需求对源码进行注入或者覆写部分代码,封装自己需要的返回字段就行!
三.源码中的Replication(是否同步复制信息)
如果集群中有 1, 2 ,3三个实例,1配2, 2配3, 3配1, 形成链式集群,那么当向1注册一个新服务时,只有1, 2两个Eureka实例会有新服务的注册信息,3是没有的。这一点在官方wiki上并没有明确说明。
一般情况下,直接去源码的core包中翻看,不出所料,找到一个ApplicationsResource.java 其中有个getApplicationResource()方法
下一步发现ApplicationsResource委托给了ApplicationResource.java
可以发现,默认的服务注册isReplication 是从header中的"x-netflix-discovery-replication"是不是为"true"来决定的,同步请求会在header中加上自定义的x-netflix-discovery-replication头:
public static final String HEADER_REPLICATION = "x-netflix-discovery-replication";
假如现在传入的isReplication=ture我们继续往下走来到它的实现类 PeerAwareInstanceRegistryImpl.java :275行
public void register(InstanceInfo info, boolean isReplication) {
int leaseDuration = 90;
if (info.getLeaseInfo() != null && info.getLeaseInfo().getDurationInSecs() > 0) {
leaseDuration = info.getLeaseInfo().getDurationInSecs();
}
//调用父类的注册方法
super.register(info, leaseDuration, isReplication);
//然后调用同步方法(本类415行)假如此时isReplication为true
this.replicateToPeers(PeerAwareInstanceRegistryImpl.Action.Register, info.getAppName(), info.getId(), info, (InstanceStatus)null, isReplication);
}
PeerAwareInstanceRegistryImpl.java :415行
private void replicateToPeers(PeerAwareInstanceRegistryImpl.Action action, String appName, String id, InstanceInfo info, InstanceStatus newStatus, boolean isReplication) {
//时间日志工具先不管
Stopwatch tracer = action.getTimer().start();
try {
if (isReplication) {
//最小重复次数自增1L
this.numberOfReplicationsLastMin.increment();
}
// 看条件如果peerEurekaNodes (集群是否为空)
//但是假设isReplication 为true, 是个同步注册信息的请求
//这个本来就是复制同步请求,那么就不在进行同步复制,避免重复数据!
if (this.peerEurekaNodes != Collections.EMPTY_LIST && !isReplication) {
Iterator var8 = this.peerEurekaNodes.getPeerEurekaNodes().iterator();
// 向自己的peer节点同步注册信息
while(var8.hasNext()) {
PeerEurekaNode node = (PeerEurekaNode)var8.next();
if (!this.peerEurekaNodes.isThisMyUrl(node.getServiceUrl())) {
this.replicateInstanceActionsToPeers(action, appName, id, info, newStatus, node);
}
}
return;
}
} finally {
tracer.stop();
}
}
假设isReplication 为true, 是个同步注册信息的请求(!isReplication)这里就直接返回false了 目前源码版本为:1.9.13
还有个不知名的版本源码是这样的:
private void replicateToPeers(Action action, String appName, String id,
InstanceInfo info /* optional */,
InstanceStatus newStatus /* optional */, boolean isReplication) {
Stopwatch tracer = action.getTimer().start();
try {
// ... ...
// isReplication=ture这里就直接返回了
if (peerEurekaNodes == Collections.EMPTY_LIST || isReplication) {
return;
}
for (final PeerEurekaNode node : peerEurekaNodes.getPeerEurekaNodes()) {
if (peerEurekaNodes.isThisMyUrl(node.getServiceUrl())) {
continue;
}
replicateInstanceActionsToPeers(action, appName, id, info, newStatus, node);
}
} finally {
tracer.stop();
}
}
尝试看看最新版本中是不是有所变化,于是引入最新maven试试:
很遗憾的是,目前最新版本1.9.22中和1.9.13的源码是一样的,所以关于二次注册同步的问题.是作者有意而为之,并不是bug.
,是为了集群中的注册表中最大限度的避免重复数据!
四.总结
1.需要封装自己的eureka服务的可以参看本次记录,甚至可以集成部分CRUD页面,做一个服务的维护增强,因为我就是这样做的,哈哈哈哈!
2.需要研究二次注册问题的,可以继续深挖,看看最后还有什么是本人没有发现的,期待有大神解决了艾特一下我!