【Spring Cloud】SpringCloud 如何集成 Eureka-Server

329 阅读3分钟

这是我参与更文挑战的第8天,活动详情查看:更文挑战

一、前言

对应 eureka-server 详细源码分析: 链接


spring-cloud-starter-eureka-server 项目,就是对 eureka-server 进行了封装的 spring boot 项目。对应的官网:github.com/spring-clou…


既然都学习了 eureka-server 了,为什么还要学习 spring-cloud-starter-eureka-server

  1. 学习 spring-cloud 如何封装 eureka-server
  2. 学习 spring-cloud 如何启动 eureka-server

spring boot 集成 eureka-server 只需要加个注解 @EnableEurekaServer,代码如下:

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

提前小结

问题:

  1. spring-cloud 如何封装 eureka-server
  2. spring-cloud 如何启动 eureka-server

1. spring-cloud 如何启动 eureka-server

启动主要分为两大步:

  1. spring boot 启动后,将内嵌 tomcat 容器启动,把自身作为一个 web 应用启动

  2. 跟着 @EnableEurekaServer 注解,完成初始化,从而实现原来 Bootstrap

    1. EurekaServerAutoConfiguration 初始化

    2. EurekaServerInitializerConfiguration 初始化

    3. EurekaServerBootstrap : 对应着 eureka-server 初始化

以上第二大步完成 eureka server 的所有组件的初始化,并将 eukrea server 启动。


2. 学习 spring-cloud 如何封装 eureka-server

最容易想到的是,直接拷贝代码。

但拷贝代码,又要减少耦合,保证个模块独立性,那么就需要 spring boot 的特征自动装配。

步骤可分为:

  1. eureka-server 初始化代码,进行了封装:
  2. 利用 spring boot 的特性,改写代码:bean 的生成、配置的加载
  3. eureka-server 的配置文件打包:将配置集成进 application.yml,并赋值对应默认值


二、直接怼源码

着手点就是 @EnableEurekaServer

@EnableEurekaServer 注解:就是在 spring boot 将自身的 web 容器启动之后,再把 eureka-server 启动起来。

@EnableEurekaServer 入手,主要看三个类,也可叫为三个步骤:

  1. EurekaServerAutoConfiguration 初始化
  2. EurekaServerInitializerConfiguration 初始化
  3. 重要:EurekaServerBootstrap 初识化

IDEA 中按 CTRL + 点击 进入 @EnableEurekaServer,源码如下:

/**
 * Annotation to activate Eureka Server related configuration {@link EurekaServerAutoConfiguration}
 *
 * @author Dave Syer
 * @author Biju Kunjummen
 *
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(EurekaServerMarkerConfiguration.class)
public @interface EnableEurekaServer {
}

  1. EurekaServerAutoConfiguration 初始化

@EnableEurekaServer 会触发 EurekaServerAutoConfiguration 初始化,代码如下:

@Configuration // 标识是配置类
// 先执行,并生成对应的 bean
@Import(EurekaServerInitializerConfiguration.class)
// 当 Marker 对象被初始化并加载到 spring 容器中,这个配置才能加载
@ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class) 
// 从配置文件加载配置信息到这两个 bean 中
@EnableConfigurationProperties({ EurekaDashboardProperties.class,
		InstanceRegistryProperties.class })
// 加载默认配置文件
@PropertySource("classpath:/eureka/server.properties")
// 继承,目的将 eureka-server 的 jersey 拦截器信息注册到 springmvc 中
public class EurekaServerAutoConfiguration extends WebMvcConfigurerAdapter {

    // 初始化一大堆 eureka server 组件
    // 并将这些组件生成对应 bean,加载进 spring 容器中
    ... ...
}

  1. EurekaServerInitializerConfiguration 初始化

@Import(EurekaServerInitializerConfiguration.class),看类名就知道是初始化配置,其源码如下:

@Configuration
public class EurekaServerInitializerConfiguration
		implements ServletContextAware, SmartLifecycle, Ordered {
    
    // 值得说明的一点:SmartLifecycle ,在 bean 加载初始化完成之后,会调用其 start() 方法。
    
    // 注入一堆 bean
    ... ...
	
    
    // 通过实现 SmartLifecycle,在 spring 生命周期调用
	@Override
	public void start() {
        // 另起一线程运行
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    // 重要:初始化 eureka-server 
                    eurekaServerBootstrap.contextInitialized(
                        EurekaServerInitializerConfiguration.this.servletContext);
                    ... ...
                }
                catch (Exception ex) {
                    ... ...
                }
            }
        }).start();
	}
}

  1. EurekaServerBootstrap 初始化

这块就可以对照 eureka-server 源码分析来看啦!!!

public class EurekaServerBootstrap {
    public void contextInitialized(ServletContext context) {
        try {
            // 1. 初始化环境变量
            initEurekaEnvironment();
            // 2. 初始化上下文
            initEurekaServerContext();

            context.setAttribute(EurekaServerContext.class.getName(), this.serverContext);
        }
        catch (Throwable e) {
            log.error("Cannot bootstrap eureka server :", e);
            throw new RuntimeException("Cannot bootstrap eureka server :", e);
        }
    }
}