06-Eureka服务注册核心源码解析
目录
2、Eureka服务注册核心源码解析
2.1、EnableEurekaServer注解作用
2.2、自动装载核心配置类
2.3、EurekaServerInitializerConfiguration
2.4、EurekaServerAutoConfiguration
2.5、暴露的服务端接口
2.6、服务剔除
2、Eureka服务注册核心源码解析
2.1、EnableEurekaServer注解作用
通过 @EnableEurekaServer 激活EurekaServer
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({EurekaServerMarkerConfiguration.class})
public @interface EnableEurekaServer {
}
此类有一个重要作用:导入EurekaServerMarkerConfiguration配置类实例化了一个Marker的bean对
象,此对象是实例化核心配置类的前提条件
@Configuration
public class EurekaServerMarkerConfiguration {
public EurekaServerMarkerConfiguration() {
}
@Bean
public EurekaServerMarkerConfiguration.Marker eurekaServerMarkerBean() {
return new EurekaServerMarkerConfiguration.Marker();
}
class Marker {
Marker() {
}
}
}
2.2、自动装载核心配置类
SpringCloud对EurekaServer的封装使得发布一个EurekaServer无比简单,根据自动装载原则可以在spring-cloud-netflix-eureka-server-2.1.0.RELEASE.jar 下找到 spring.factories
EurekaServerAutoConfiguration 是Eureka服务端的自动配置类
@Configuration
@Import({EurekaServerInitializerConfiguration.class})
@ConditionalOnBean({Marker.class})
@EnableConfigurationProperties({EurekaDashboardProperties.class,
InstanceRegistryProperties.class})
@PropertySource({"classpath:/eureka/server.properties"})
public class EurekaServerAutoConfiguration extends WebMvcConfigurerAdapter {
//...代码省略
}
现在我们展开来说这个Eureka服务端的自动配置类;
1. 这个配置类实例化的前提条件是上下文中存在 EurekaServerMarkerConfiguration.Marker 这个bean,解释了上面的问题
2. 通过@EnableConfigurationProperties({ EurekaDashboardProperties.class, InstanceRegistryProperties.class })导入了两个配置类
1. EurekaDashboardProperties : 配置 EurekaServer的管控台
2. InstanceRegistryProperties : 配置期望续约数量和默认的通信数量
3. 通过@Import({EurekaServerInitializerConfiguration.class})引入启动配置类
2.3、EurekaServerInitializerConfiguration
@Configuration
public class EurekaServerInitializerConfiguration implements
ServletContextAware, SmartLifecycle, Ordered {
public void start() {
(new Thread(new Runnable() {
public void run() {
try {
EurekaServerInitializerConfiguration.this.eurekaServerBootstrap.contextInitiali
zed(EurekaServerInitializerConfiguration.this.servletContext);
EurekaServerInitializerConfiguration.log.info("Started
Eureka Server");
EurekaServerInitializerConfiguration.this.publish(new
EurekaRegistryAvailableEvent(EurekaServerInitializerConfiguration.this.getEureka
ServerConfig()));
EurekaServerInitializerConfiguration.this.running = true;
EurekaServerInitializerConfiguration.this.publish(new
EurekaServerStartedEvent(EurekaServerInitializerConfiguration.this.getEurekaServ
erConfig()));
} catch (Exception var2) {
EurekaServerInitializerConfiguration.log.error("Could not
initialize Eureka servlet context", var2);
}
}
})).start();
}
可以看到EurekaServerInitializerConfiguration实现了SmartLifecycle,也就意味着Spring容器启动时
会去执行start()方法。加载所有的EurekaServer的配置
2.4、EurekaServerAutoConfiguration
实例化了EurekaServer的管控台的Controller类 EurekaController
@Bean
@ConditionalOnProperty(
prefix = "eureka.dashboard",
name = {"enabled"},
matchIfMissing = true
)
public EurekaController eurekaController() {
return new EurekaController(this.applicationInfoManager);
}
实例化EurekaServerBootstrap类
@Bean
public EurekaServerBootstrap eurekaServerBootstrap(PeerAwareInstanceRegistry
registry, EurekaServerContext serverContext) {
return new EurekaServerBootstrap(this.applicationInfoManager,
this.eurekaClientConfig, this.eurekaServerConfig, registry, serverContext);
}
实例化jersey相关配置类
@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;
}
@Bean
public Application jerseyApplication(Environment environment, ResourceLoader
resourceLoader) {
ClassPathScanningCandidateComponentProvider provider = new
ClassPathScanningCandidateComponentProvider(false, environment);
provider.addIncludeFilter(new AnnotationTypeFilter(Path.class));
provider.addIncludeFilter(new AnnotationTypeFilter(Provider.class));
Set<Class<?>> classes = new HashSet();
String[] var5 = EUREKA_PACKAGES;
int var6 = var5.length;
for(int var7 = 0; var7 < var6; ++var7) {
String basePackage = var5[var7];
Set<BeanDefinition> beans =
provider.findCandidateComponents(basePackage);
Iterator var10 = beans.iterator();
while(var10.hasNext()) {
BeanDefinition bd = (BeanDefinition)var10.next();
Class<?> cls =
ClassUtils.resolveClassName(bd.getBeanClassName(),
resourceLoader.getClassLoader());
classes.add(cls);
}
}
Map<String, Object> propsAndFeatures = new HashMap();
propsAndFeatures.put("com.sun.jersey.config.property.WebPageContentRegex",
"/eureka/(fonts|images|css|js)/.*");
DefaultResourceConfig rc = new DefaultResourceConfig(classes);
rc.setPropertiesAndFeatures(propsAndFeatures);
return rc;
}
jerseyApplication 方法,在容器中存放了一个jerseyApplication对象,jerseyApplication()方法里的
东西和Spring源码里扫描@Component逻辑类似,扫描@Path和@Provider标签,然后封装成
beandefinition,封装到Application的set容器里。通过filter过滤器来过滤url进行映射到对象的
Controller
2.5、暴露的服务端接口
由于集成了Jersey,我们可以找到在EurekaServer的依赖包中的 eureka-core-1.9.8.jar ,可以看到一些列的XXXResource
这些类都是通过Jersey发布的供客户端调用的服务接口。
(1)服务端接受客户端的注册
在ApplicationResource.addInstance()方法中可以看到 this.registry.register(info,
"true".equals(isReplication));

public void register(InstanceInfo info, boolean isReplication) {
//默认有效时长90m
int leaseDuration = 90;
if (info.getLeaseInfo() != null &&
info.getLeaseInfo().getDurationInSecs() > 0) {
leaseDuration = info.getLeaseInfo().getDurationInSecs();
}
//注册实例
super.register(info, leaseDuration, isReplication);
//同步到其他EurekaServer服务
this.replicateToPeers(PeerAwareInstanceRegistryImpl.Action.Register,
info.getAppName(), info.getId(), info, (InstanceStatus)null, isReplication);
}
继续找到父类的register方法可以看到整个注册的过程
//线程安全的map,存放所有注册的示例对象
private final ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>>
registry = new ConcurrentHashMap();
public void register(InstanceInfo registrant, int leaseDuration, boolean
isReplication) {
try {
this.read.lock();
Map<String, Lease<InstanceInfo>> gMap =
(Map)this.registry.get(registrant.getAppName());
EurekaMonitors.REGISTER.increment(isReplication);
//如果第一个实例注册会给registryput进去一个空的
if (gMap == null) {
ConcurrentHashMap<String, Lease<InstanceInfo>> gNewMap = new
ConcurrentHashMap();
gMap = (Map)this.registry.putIfAbsent(registrant.getAppName(),
gNewMap);
if (gMap == null) {
gMap = gNewMap;
}
}
//根据注册的示例对象id,获取已存在的Lease
Lease<InstanceInfo> existingLease = (Lease)
((Map)gMap).get(registrant.getId());
if (existingLease != null && existingLease.getHolder() != null) {
Long existingLastDirtyTimestamp =
((InstanceInfo)existingLease.getHolder()).getLastDirtyTimestamp();
Long registrationLastDirtyTimestamp =
registrant.getLastDirtyTimestamp();
logger.debug("Existing lease found (existing={}, provided={}",
existingLastDirtyTimestamp, registrationLastDirtyTimestamp);
if (existingLastDirtyTimestamp > registrationLastDirtyTimestamp)
{
logger.warn("There is an existing lease and the existing
lease's dirty timestamp {} is greater than the one that is being registered {}",
existingLastDirtyTimestamp, registrationLastDirtyTimestamp);
logger.warn("Using the existing instanceInfo instead of the
new instanceInfo as the registrant");
registrant = (InstanceInfo)existingLease.getHolder();
}
} else {
Object var6 = this.lock;
synchronized(this.lock) {
if (this.expectedNumberOfClientsSendingRenews > 0) {
++this.expectedNumberOfClientsSendingRenews;
this.updateRenewsPerMinThreshold();
}
}
logger.debug("No previous lease information found; it is new
registration");
}
Lease<InstanceInfo> lease = new Lease(registrant, leaseDuration); if (existingLease != null) {
lease.setServiceUpTimestamp(existingLease.getServiceUpTimestamp());
}
//将lease存入gMap
((Map)gMap).put(registrant.getId(), lease);
AbstractInstanceRegistry.CircularQueue var20 =
this.recentRegisteredQueue;
synchronized(this.recentRegisteredQueue) {
this.recentRegisteredQueue.add(new
Pair(System.currentTimeMillis(), registrant.getAppName() + "(" +
registrant.getId() + ")"));
}
if
(!InstanceStatus.UNKNOWN.equals(registrant.getOverriddenStatus())) {
logger.debug("Found overridden status {} for instance {}.
Checking to see if needs to be add to the overrides",
registrant.getOverriddenStatus(), registrant.getId());
if
(!this.overriddenInstanceStatusMap.containsKey(registrant.getId())) {
logger.info("Not found overridden id {} and hence adding
it", registrant.getId());
this.overriddenInstanceStatusMap.put(registrant.getId(),
registrant.getOverriddenStatus());
}
}
InstanceStatus overriddenStatusFromMap =
(InstanceStatus)this.overriddenInstanceStatusMap.get(registrant.getId());
if (overriddenStatusFromMap != null) {
logger.info("Storing overridden status {} from map",
overriddenStatusFromMap);
registrant.setOverriddenStatus(overriddenStatusFromMap);
}
InstanceStatus overriddenInstanceStatus =
this.getOverriddenInstanceStatus(registrant, existingLease, isReplication);
registrant.setStatusWithoutDirty(overriddenInstanceStatus);
if (InstanceStatus.UP.equals(registrant.getStatus())) {
lease.serviceUp();
}
registrant.setActionType(ActionType.ADDED);
this.recentlyChangedQueue.add(new
AbstractInstanceRegistry.RecentlyChangedItem(lease));
registrant.setLastUpdatedTimestamp();
this.invalidateCache(registrant.getAppName(),
registrant.getVIPAddress(), registrant.getSecureVipAddress());
logger.info("Registered instance {}/{} with status {} (replication=
{})", new Object[]{registrant.getAppName(), registrant.getId(),
registrant.getStatus(), isReplication});
} finally {
this.read.unlock();
}
}
(2)服务端接受客户端的续约
在InstanceResource的renewLease方法中完成客户端的心跳(续约)处理,其中最关键的方法就是this.registry.renew(this.app.getName(), this.id, isFromReplicaNode)
public boolean renew(String appName, String id, boolean isReplication) {
//客户端续约
if (super.renew(appName, id, isReplication)) {
//同步到其他的EurekaServer服务
this.replicateToPeers(PeerAwareInstanceRegistryImpl.Action.Heartbeat, appName,
id, (InstanceInfo)null, (InstanceStatus)null, isReplication);
return true;
} else {
return false;
}
}
继续找到父类的renew方法可以看到整个续约的过程
public boolean renew(String appName, String id, boolean isReplication) {
EurekaMonitors.RENEW.increment(isReplication);
Map<String, Lease<InstanceInfo>> gMap = (Map)this.registry.get(appName);
//从内存map中根据id获取示例对象的Lease对象
Lease<InstanceInfo> leaseToRenew = null;
if (gMap != null) {
leaseToRenew = (Lease)gMap.get(id);
}
if (leaseToRenew == null) {
EurekaMonitors.RENEW_NOT_FOUND.increment(isReplication);
logger.warn("DS: Registry: lease doesn't exist, registering
resource: {} - {}", appName, id);
return false;
} else {
//获取示例对象
InstanceInfo instanceInfo = (InstanceInfo)leaseToRenew.getHolder();
if (instanceInfo != null) {
InstanceStatus overriddenInstanceStatus =
this.getOverriddenInstanceStatus(instanceInfo, leaseToRenew, isReplication);
if (overriddenInstanceStatus == InstanceStatus.UNKNOWN) {
logger.info("Instance status UNKNOWN possibly due to deleted
override for instance {}; re-register required", instanceInfo.getId());
EurekaMonitors.RENEW_NOT_FOUND.increment(isReplication);
return false;
}
if (!instanceInfo.getStatus().equals(overriddenInstanceStatus))
{
logger.info("The instance status {} is different from
overridden instance status {} for instance {}. Hence setting the status to
overridden status", new Object[]{instanceInfo.getStatus().name(),
instanceInfo.getOverriddenStatus().name(), instanceInfo.getId()});
//设置示例状态
instanceInfo.setStatusWithoutDirty(overriddenInstanceStatus);
}4.3.2.6 服务剔除
在AbstractInstanceRegistry.postInit()方法,在此方法里开启了一个每60秒调用一次
EvictionTask.evict()的定时器。
}
//设置续约次数
this.renewsLastMin.increment();
leaseToRenew.renew();
return true;
}
}
2.6、服务剔除
在AbstractInstanceRegistry.postInit()方法,在此方法里开启了一个每60秒调用一次
EvictionTask.evict()的定时器。
public void evict(long additionalLeaseMs) {
logger.debug("Running the evict task");
if (!this.isLeaseExpirationEnabled()) {
logger.debug("DS: lease expiration is currently disabled.");
} else {
List<Lease<InstanceInfo>> expiredLeases = new ArrayList();
Iterator var4 = this.registry.entrySet().iterator();
while(true) {
Map leaseMap;
do {
if (!var4.hasNext()) {
int registrySize = (int)this.getLocalRegistrySize();
int registrySizeThreshold = (int)((double)registrySize *
this.serverConfig.getRenewalPercentThreshold());
int evictionLimit = registrySize -
registrySizeThreshold;
int toEvict = Math.min(expiredLeases.size(),
evictionLimit);
if (toEvict > 0) {
logger.info("Evicting {} items (expired={},
evictionLimit={})", new Object[]{toEvict, expiredLeases.size(), evictionLimit});
Random random = new
Random(System.currentTimeMillis());
for(int i = 0; i < toEvict; ++i) {
int next = i +
random.nextInt(expiredLeases.size() - i);
Collections.swap(expiredLeases, i, next);
Lease<InstanceInfo> lease =
(Lease)expiredLeases.get(i);
String appName =
((InstanceInfo)lease.getHolder()).getAppName();
String id =
((InstanceInfo)lease.getHolder()).getId();
EurekaMonitors.EXPIRED.increment();
logger.warn("DS: Registry: expired lease for
{}/{}", appName, id);
this.internalCancel(appName, id, false);
}
}
return;
}
Entry<String, Map<String, Lease<InstanceInfo>>> groupEntry =
(Entry)var4.next();
leaseMap = (Map)groupEntry.getValue();
} while(leaseMap == null);
Iterator var7 = leaseMap.entrySet().iterator();
while(var7.hasNext()) {
Entry<String, Lease<InstanceInfo>> leaseEntry =
(Entry)var7.next();
Lease<InstanceInfo> lease = (Lease)leaseEntry.getValue();
if (lease.isExpired(additionalLeaseMs) && lease.getHolder()
!= null) {
expiredLeases.add(lease);
}
}
}
}
}

浙公网安备 33010602011771号