源码解析-Spring Eureka

源码解析-Spring Eureka

文章目录


前言


一、从Spring.factory和注解开始

我们可以看到,Eureka通过spring boot的自动配置机制引入了一个类

java 复制代码
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  org.springframework.cloud.netflix.eureka.server.EurekaServerAutoConfiguration

通过这个配置我们找到对应的配置类,可以看到,这个配置类使用了Marker作为条件注入

java 复制代码
@Configuration(
    proxyBeanMethods = false
)
@Import({EurekaServerInitializerConfiguration.class})
@ConditionalOnBean({EurekaServerMarkerConfiguration.Marker.class})
@EnableConfigurationProperties({EurekaDashboardProperties.class, InstanceRegistryProperties.class})
@PropertySource({"classpath:/eureka/server.properties"})
public class EurekaServerAutoConfiguration implements WebMvcConfigurer

这个时候我们返回查看我们配置一个eureka所需要的基本注解可以看到,我们正在这个这个@EnableEurekaServer 注解里面初始化了这个类

java 复制代码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.cloud.netflix.eureka.server;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({EurekaServerMarkerConfiguration.class})
public @interface EnableEurekaServer {
}

通过spring.factory的自动配置以及@EnableEurekaServer 就可以实现eureka服务端的手动注入(通过加入注解)

二、重要的一步EurekaServerInitializerConfiguration

在上面的EurekaServerAutoConfiguration里面我们可以看到它import了一个初始化类

注意在这个初始化类实现了SmartLifeCycle接口,实现了其Start方法

java 复制代码
@Configuration(
    proxyBeanMethods = false
)
public class EurekaServerInitializerConfiguration implements ServletContextAware, SmartLifecycle, Ordered 

实现的start方法,会在bean在启动的时候调用,该方法会new一个线程并发布订阅

java 复制代码
    public void start() {
        (new Thread(() -> {
            try {
                this.eurekaServerBootstrap.contextInitialized(this.servletContext);
                log.info("Started Eureka Server");
                this.publish(new EurekaRegistryAvailableEvent(this.getEurekaServerConfig()));
                this.running = true;
                this.publish(new EurekaServerStartedEvent(this.getEurekaServerConfig()));
            } catch (Exception var2) {
                log.error("Could not initialize Eureka servlet context", var2);
            }

        })).start();
    }

可以看到,通过这个start方法,eureka初始化了它自己的context上下文并发布了一些事件。

三、初始化了什么?

进入到contextInitialized方法,我们可以看到

java 复制代码
 public void contextInitialized(ServletContext context) {
        try {
            this.initEurekaEnvironment();
            this.initEurekaServerContext();
            context.setAttribute(EurekaServerContext.class.getName(), this.serverContext);
        } catch (Throwable var3) {
            log.error("Cannot bootstrap eureka server :", var3);
            throw new RuntimeException("Cannot bootstrap eureka server :", var3);
        }
    }

eureka首先初始化了配置信息,然后进行上下文的初始化

java 复制代码
 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();
        }

        EurekaServerContextHolder.initialize(this.serverContext);
        log.info("Initialized server context");
        int registryCount = this.registry.syncUp();
        this.registry.openForTraffic(this.applicationInfoManager, registryCount);
        EurekaMonitors.registerAllStats();
    }

进入到initEurekaServerContext方法,我们可以看到几个重要的方法

在openForTraffic方法里面

java 复制代码
 public void openForTraffic(ApplicationInfoManager applicationInfoManager, int count) {
        this.expectedNumberOfClientsSendingRenews = count;
        this.updateRenewsPerMinThreshold();
        logger.info("Got {} instances from neighboring DS node", count);
        logger.info("Renew threshold is: {}", this.numberOfRenewsPerMinThreshold);
        this.startupTime = System.currentTimeMillis();
        if (count > 0) {
            this.peerInstancesTransferEmptyOnStartup = false;
        }

        DataCenterInfo.Name selfName = applicationInfoManager.getInfo().getDataCenterInfo().getName();
        boolean isAws = Name.Amazon == selfName;
        if (isAws && this.serverConfig.shouldPrimeAwsReplicaConnections()) {
            logger.info("Priming AWS connections for all replicas..");
            this.primeAwsReplicas(applicationInfoManager);
        }

        logger.info("Changing status to UP");
        applicationInfoManager.setInstanceStatus(InstanceStatus.UP);
        super.postInit();
    }

我们重点关注这里的super.postInit()

java 复制代码
  protected void postInit() {
        this.renewsLastMin.start();
        if (this.evictionTaskRef.get() != null) {
            ((EvictionTask)this.evictionTaskRef.get()).cancel();
        }

        this.evictionTaskRef.set(new EvictionTask());
        this.evictionTimer.schedule((TimerTask)this.evictionTaskRef.get(), this.serverConfig.getEvictionIntervalTimerInMs(), this.serverConfig.getEvictionIntervalTimerInMs());
    }

可以看到this.evictionTaskRef.set(new EvictionTask());,这里注册了一个剔除任务

java 复制代码
int registrySize = (int)this.getLocalRegistrySize();
                        int registrySizeThreshold = (int)((double)registrySize * this.serverConfig.getRenewalPercentThreshold());
                        int evictionLimit = registrySize - registrySizeThreshold;
                        int toEvict = Math.min(expiredLeases.size(), evictionLimit);

这里的剔除与eureka配置里面的自我保护配置有关

自动保护

在eureka中,如果打开了自我保护配置并设置了剔除阈值,eureka集群就会在计算正常超过阈值的时候执行上面的代码把的节点给剔除

  1. 如果现在有10个节点,7个节点是正常,3个节点是由有问题的,阈值设置了80%,这个时候7个节点中的一个节点出现了问题,但是没有超过阈值(变成了60%),这个时候就会访问到失败的节点
  2. 如果现在有100个节点,3个节点有问题,阈值也是80%,现在的值是(97%)超过了阈值,如果这个时候有节点出现问题则会立即剔除,
  3. 但是不能把自我保护关闭,如果3个节点是因为波动导致的暂时访问不到则会立即被剔除
java 复制代码
eureka:
  server:
    enable-self-preservation: true
eureka:
  server:
    renewal-percent-threshold: 0.85
相关推荐
天天向上杰1 分钟前
简识JVM的栈帧优化共享技术
java·jvm
方圆想当图灵20 分钟前
缓存之美:万文详解 Caffeine 实现原理(下)
java·redis·缓存
栗豆包35 分钟前
w175基于springboot的图书管理系统的设计与实现
java·spring boot·后端·spring·tomcat
等一场春雨1 小时前
Java设计模式 十四 行为型模式 (Behavioral Patterns)
java·开发语言·设计模式
酱学编程2 小时前
java中的单元测试的使用以及原理
java·单元测试·log4j
我的运维人生3 小时前
Java并发编程深度解析:从理论到实践
java·开发语言·python·运维开发·技术共享
一只爱吃“兔子”的“胡萝卜”3 小时前
2.Spring-AOP
java·后端·spring
HappyAcmen3 小时前
Java中List集合的面试试题及答案解析
java·面试·list
Ase5gqe3 小时前
Windows 配置 Tomcat环境
java·windows·tomcat
大乔乔布斯3 小时前
JRE、JVM 和 JDK 的区别
java·开发语言·jvm