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);
                  }
              }
          }
      }
  }
 
 
posted @ 2022-04-03 22:59  HvH95  阅读(215)  评论(0)    收藏  举报