Eureka Server集群部署 部署环境:
IDEA
Windows10
Eureka-1.10.7
Gradle
1.依赖文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 plugins { id 'org.springframework.boot' version '2.3.7.RELEASE' id 'io.spring.dependency-management' version '1.0.10.RELEASE' id 'java' } group = 'com.isspark.cloud' version = '0.0.1-SNAPSHOT' sourceCompatibility = '1.8' repositories { maven { url 'https://maven.aliyun.com/repository/gradle-plugin' } maven { url 'https://maven.aliyun.com/repository/google' } maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' } maven { url 'https://maven.aliyun.com/repository/jcenter' } } ext { set('springCloudVersion' , "Hoxton.SR9" ) } dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server' testImplementation('org.springframework.boot:spring-boot-starter-test' ) { exclude group : 'org.junit.vintage' , module: 'junit-vintage-engine' } } dependencyManagement { imports { mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" } } test { useJUnitPlatform() }
2.配置文件dev.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 server: servlet: context-path: /cloud port: 8761 spring: profiles: active: dev application: name: cloud1 server: servlet: context-path: /cloud port: 8762 spring: profiles: active: dev application: name: cloud2 server: servlet: context-path: /cloud port: 8763 spring: profiles: active: dev application: name: cloud3
3.配置Eureka在application-dev.yml文件中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 eureka: instance: prefer-ip-address: false hostname: "eureka-cluster1" server: enable-self-preservation: true client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://eureka-cluster2:8762/cloud/eureka spring: freemarker: prefer-file-system-access: false eureka: instance: prefer-ip-address: false hostname: "eureka-cluster2" server: enable-self-preservation: true client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://eureka-cluster1:8761/cloud/eureka spring: freemarker: prefer-file-system-access: false eureka: instance: prefer-ip-address: false hostname: "eureka-cluster3" server: enable-self-preservation: true client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://eureka-cluster1:8761/cloud/eureka spring: freemarker: prefer-file-system-access: false
4.配置windows的host配置
1 2 3 127.0.0.1 eureka-cluster1 127.0.0.1 eureka-cluster2 127.0.0.1 eureka-cluster3
5.访问http://localhost:8761/cloud/ ,如下截图
需要注意上面的配置中defaultZone的配置地址上下文一定要加上dev.yaml配置的context-path,不然会注册失败。
上面我们启动三个实例eureka-cluster1-3,启动后我们访问 http://localhost:8761/cloud/ 可以看到注册的实例。需要注意我们开启了Eureka自我保护模式,一旦下线超过85%就会提示开启保护模式,Eureka服务端将不会将实例信息从注册信息表中删除。
Eureka服务端启动过程 从@EnableEurekaServer开始 查看EnableEurekaServer注解源码:
1 2 3 4 5 6 7 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(EurekaServerMarkerConfiguration.class) public @interface EnableEurekaServer {}
关注@Import注解,引入了配置类EurekaServerMarkerConfiguration,并把该配置类下的@Bean加入到容器中,源码如下:
1 2 3 4 5 6 7 8 9 @Configuration(proxyBeanMethods = false) public class EurekaServerMarkerConfiguration { @Bean public Marker eurekaServerMarkerBean () { return new Marker(); } class Marker { } }
这里我们看到EurekaServerMarkerConfiguration 配置类把一个名为eurekaServerMarkerBean 的Mark类加入容器。该类的作用就是一个激活标记。后面有用到。
从EurekaServerAutoConfiguration开始 在spring-cloud-netflix-eureka-server-2.2.6.RELEASE.jar包的META—INFO目录下,我们看到spring.factories文件配置如下:
1 2 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.netflix.eureka.server.EurekaServerAutoConfiguration
这表示EurekaServerAutoConfiguration会在Spring启动的时候会进行实例化。
spring factories是spring boot提供的一种扩展机制,和SPI类似。知识点参考:Creating Your Own Auto-configuration 和Creating Extensible Applications
下面我们再看下EurekaServerAutoConfiguration,源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @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 { @Bean public HasFeatures eurekaServerFeature () { return HasFeatures.namedFeature("Eureka Server" , EurekaServerAutoConfiguration.class); } }
@Configuration注解声明该类是个配置类。
@Import 注解引入了一个配置类EurekaServerInitializerConfiguration,Eureka初始化启动类;
@ConditionalOnBean 表明只有在SPRING容器中有EurekaServerMarkerConfiguration.Marker类的时候才加载EurekaServerAutoConfiguration。
@EnableConfigurationProperties,加载Eureka仪表盘配置和实例注册配置。
@PropertySource,加载server.properties配置
我们先看EurekaServerInitializerConfiguration,发现实现了三个类ServletContextAware, SmartLifecycle, Ordere。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 @Configuration(proxyBeanMethods = false) public class EurekaServerInitializerConfiguration implements ServletContextAware , SmartLifecycle , Ordered { private static final Log log = LogFactory .getLog(EurekaServerInitializerConfiguration.class); @Autowired private EurekaServerConfig eurekaServerConfig; private ServletContext servletContext; @Autowired private ApplicationContext applicationContext; @Autowired private EurekaServerBootstrap eurekaServerBootstrap; private boolean running; private int order = 1 ; @Override public void setServletContext (ServletContext servletContext) { this .servletContext = servletContext; } @Override public void start () { new Thread(() -> { try { eurekaServerBootstrap.contextInitialized( EurekaServerInitializerConfiguration.this .servletContext); log.info("Started Eureka Server" ); publish(new EurekaRegistryAvailableEvent(getEurekaServerConfig())); EurekaServerInitializerConfiguration.this .running = true ; publish(new EurekaServerStartedEvent(getEurekaServerConfig())); } catch (Exception ex) { log.error("Could not initialize Eureka servlet context" , ex); } }).start(); } }
我们看到该接口实现了SmartLifecycle,表示在SPRING容器加载完所有bean之后,就会回调实现该接口的类的start()方法。start()方法中主要执行了eurekaServerBootstrap.contextInitialized()来初始化Eureka的上下问。以及发布了两个事件(我们可以通过监听该事件来实现一个自定义的操作)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public void contextInitialized (ServletContext context) { try { initEurekaEnvironment(); 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); } } protected void initEurekaServerContext () throws Exception { JsonXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(), XStream.PRIORITY_VERY_HIGH); XmlXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(), XStream.PRIORITY_VERY_HIGH); if (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(); }
上面是contextInitialized方法中的内容,主要初始化环境和上下文。我们先看this.registry.syncUp()
参考资料 【1】SpringCloud的server端之EurekaServerAutoConfiguration介绍
【2】Creating Your Own Auto-configuration
【3】Creating Extensible Applications
【4】 Eureka Wiki
Author:
Desperado
Permalink:
http://xstar.life/2022/06/17/eurekaServerStart/
License:
Copyright (c) 2019 CC-BY-NC-4.0 LICENSE
Slogan:
Do you believe in DESTINY ?