Spring Cloud Eureka源码分析之服务注册的流程与数据存储设计

本文深入分析了Spring Cloud Eureka的服务注册流程,从自动注册触发机制到服务注册细节,包括EurekaServiceRegistry.register、DiscoveryClient的初始化和定时任务。同时,探讨了Eureka Server如何存储注册信息,通过PeerAwareInstanceRegistryImpl.register实现服务注册并同步到集群。
摘要由CSDN通过智能技术生成

Spring Cloud是一个生态,它提供了一套标准,这套标准可以通过不同的组件来实现,其中就包含服务注册/发现、熔断、负载均衡等,在spring-cloud-common这个包中,org.springframework.cloud.client.serviceregistry路径下,可以看到一个服务注册的接口定义ServiceRegistry。它就是定义了spring cloud中服务注册的一个接口。

public interface ServiceRegistry<R extends Registration> {
    void register(R registration);

    void deregister(R registration);

    void close();

    void setStatus(R registration, String status);

    <T> T getStatus(R registration);
}

我们看一下它的类关系图,这个接口有一个唯一的实现EurekaServiceRegistry。表示采用的是Eureka Server作为服务注册中心。

自动注册的触发机制

Eureka自动注册,是通过EurekaAutoServiceRegistration这个对象来触发的。

在Spring Boot项目启动时,会基于自动装配机制,在EurekaClientAutoConfiguration这个配置类中,初始化一个EurekaAutoServiceRegistration这个Bean对象,代码如下。

public class EurekaClientAutoConfiguration {
    @Bean
    @ConditionalOnBean(AutoServiceRegistrationProperties.class)
    @ConditionalOnProperty(
        value = "spring.cloud.service-registry.auto-registration.enabled",
        matchIfMissing = true)
    public EurekaAutoServiceRegistration eurekaAutoServiceRegistration(
        ApplicationContext context, EurekaServiceRegistry registry,
        EurekaRegistration registration) {
        return new EurekaAutoServiceRegistration(context, registry, registration);
    }
}
EurekaAutoServiceRegistration这个类的定义如下。
public class EurekaAutoServiceRegistration implements AutoServiceRegistration,
SmartLifecycle, Ordered, SmartApplicationListener {
    //省略
    @Override
    public void start() {
        // only set the port if the nonSecurePort or securePort is 0 and this.port != 0
        if (this.port.get() != 0) {
            if (this.registration.getNonSecurePort() == 0) {
                this.registration.setNonSecurePort(this.port.get());
            }

            if (this.registration.getSecurePort() == 0 && this.registration.isSecure()) {
                this.registration.setSecurePort(this.port.get());
            }
        }

        // only initialize if nonSecurePort is greater than 0 and it isn't already running
        // because of containerPortInitializer below
        if (!this.running.get() && this.registration.getNonSecurePort() > 0) {

            this.serviceRegistry.register(this.registration);

            this.context.publishEvent(new InstanceRegisteredEvent<>(this,
                                                                    this.registration.getInstanceConfig()));
            this.running.set(true);
        }
    }
    //省略...
}

我们发现,EurekaAutoServiceRegistration实现了SmartLifecycle接口,当Spring容器加载完所有的Bean并且初始化之后,会继续回调实现了SmartLifeCycle接口的类中对应的方法,比如(start)。

SmartLifeCycle知识拓展

 

我拓展一下SmartLifeCycle这块的知识, SmartLifeCycle是一个接口,当Spring容器加载完所有的Bean并且初始化之后,会继续回调实现了SmartLifeCycle接口的类中对应的方法,比如(start)。

实际上我们自己也可以拓展,比如在springboot工程的main方法同级目录下,写一个测试类,实现SmartLifeCycle接口,并且通过@Service声明为一个bean,因为要被spring去加载,首先得是bean。

@Service
public class TestSmartLifeCycle implements SmartLifecycle {
    @Override
    public void start() {
        System.out.println("start");
    }

    @Override
    public void stop() {
        System.out.println("stop");
    }

    @Override
    public boolean isRunning() {
        return false;
    }
}

接着,我们启动spring boot应用后,可以看到控制台输出了start字符串。

我们在DefaultLifecycleProcessor.startBeans方法上加一个debug,可以很明显的看到我们自己定义的TestSmartLifeCycle被扫描到了,并且最后会调用该bean的start方法。

在startBeans方法中,我们可以看到它首先会获得所有实现了SmartLifeCycle的Bean,然后会循环调用实现了SmartLifeCycle的bean的start方法,代码如下。

private void startBeans(boolean autoStartupOnly) {
    Map<String, Lifecycle> lifecycleBeans = this.getLifecycleBeans();
    Map<Integer, DefaultLifecycleProcessor.LifecycleGroup> phases = new HashMap();
    lifecycleBeans.forEach((beanName, bean) -> {
        if (!autoStartupOnly || bean instanceof SmartLifecycle && ((SmartLifecycle)bean).isAutoStartup()) {
            int phase = this.getPhase(bean);
            DefaultLifecycleProcessor.LifecycleGroup group = (DefaultLifecycleProcessor.LifecycleGroup)phases.get(phase);
            if (group == null) {
                group = new DefaultLifecycleProcessor.LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
                phases.put(phase, group);
            }

            group.add(beanName, bean);
        }

    });
    if (!phases.isEmpty()) {
        List<Integer> keys = new ArrayList(phases.keySet());
        Collections.sort(keys);
        Iterator var5 = keys.iterator();

        while(var5.hasNext()) {
            Integer key = (Integer)var5.next();
            ((DefaultLifecycleProcessor.LifecycleGroup)phases.get(key)).start(); //循环调用实现了SmartLifeCycle接口的start方法。
        }
    }

}

SmartLifeCycle接口的回调,是在SpringBoot启动时触发,具体的执行路径如下!

SpringApplication.run() -> this.refreshContext(context);->this.refresh(context);->ServletWebServerApplicationContext.refresh()->this.finishRefresh();->AbstractApplicationContext.finishRefresh->DefaultLifecycleProcessor.onRefresh()-> this.startBeans->this.start()->this.doStart()->

服务注册

因此,当SpringBoot启动时,会触发在EurekaAutoServiceRegistration中的start方法,代码如下。

public class EurekaAutoServiceRegistration implements AutoServiceRegistration,
SmartLifecycle, Ordered, SmartApplicationListener {
    //省略
    @Override
    public void start() {
        // only set the port if the nonSecurePort or securePort is 0 and this.port != 0
        if (this.port.get() != 0) {
            if (this.registration.getNonSecurePort() == 0) {
                this.registration.setNonSecurePort(this.port.get());
            }

            if (this.registration.getSecurePort() == 0 && this.registration.isSecure()) {
                this.registration.setSecurePort(this.port.get());
            }
        }

        // only initialize if nonSecurePort is greater than 0 and it isn't already running
        // because of containerPortInitializer below
        if (!this.running.get() && this.registration.getNonSecurePort() > 0) {
            //实现服务注册。
            this.serviceRegistry.register(this.registration);
            //发布一个事件
            this.context.publishEvent(new InstanceRegisteredEvent<>(this,
                                                                    this.registration.getInstanceConfig()));
            this.running.set(true);
        }
    }
    //省略...
}

EurekaServiceRegistry.register

this.serviceRegistry.register(this.registration);,实际调用的是EurekaServiceRegistry这个对象中的register方法,代码如下。

public class EurekaServiceRegistry implements ServiceRegistry<EurekaRegistration> {

    private static final Log log = LogFactory.getLog(EurekaServiceRegistry.class);

    @Override
    public void register(EurekaRegistration reg) {
        maybeInitializeClient(reg);

        if (log.isInfoEnabled()) {
            log.info("Registering application "
                    + reg.getApplicationInfoManager().getInfo().getAppName()
                    + " with eureka with status "
                    + reg.getInstanceConfig().getInitialStatus());
        }
 //设置当前实例的状态,一旦这个实例的状态发生变化,只要状态不是DOWN,
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值