Spring Cloud Eureka源码解析之Eureka Server启动流程(一)

╰半夏微凉° 2022-09-16 04:52 295阅读 0赞

通过在启动类上添加@EnableEurekaServer注解启用EurekaServer

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Import(EurekaServerMarkerConfiguration.class)
  5. public @interface EnableEurekaServer {
  6. }

该注解引入了一个配置类EurekaServerMarkerConfiguration

  1. @Configuration
  2. public class EurekaServerMarkerConfiguration {
  3. @Bean
  4. public Marker eurekaServerMarkerBean() {
  5. return new Marker();
  6. }
  7. class Marker {
  8. }
  9. }

看到就只建了一个空类,暂时不清楚干嘛用的,注解只能分析到这,接着看自动装配类
在这里插入图片描述
只有一个EurekaServerAutoConfiguration类

  1. @Configuration
  2. @Import(EurekaServerInitializerConfiguration.class)
  3. @ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class)
  4. @EnableConfigurationProperties({ EurekaDashboardProperties.class,
  5. InstanceRegistryProperties.class })
  6. @PropertySource("classpath:/eureka/server.properties")
  7. public class EurekaServerAutoConfiguration extends WebMvcConfigurerAdapter {
  8. /** * List of packages containing Jersey resources required by the Eureka server */
  9. private static final String[] EUREKA_PACKAGES = new String[] { "com.netflix.discovery",
  10. "com.netflix.eureka" };
  11. @Autowired
  12. private ApplicationInfoManager applicationInfoManager;
  13. @Autowired
  14. private EurekaServerConfig eurekaServerConfig;
  15. @Autowired
  16. private EurekaClientConfig eurekaClientConfig;
  17. @Autowired
  18. private EurekaClient eurekaClient;
  19. @Autowired
  20. private InstanceRegistryProperties instanceRegistryProperties;
  21. public static final CloudJacksonJson JACKSON_JSON = new CloudJacksonJson();
  22. }

先看类上的注解
引入EurekaServerInitializerConfiguration类

  1. @Configuration
  2. public class EurekaServerInitializerConfiguration
  3. implements ServletContextAware, SmartLifecycle, Ordered {
  4. private static final Log log = LogFactory.getLog(EurekaServerInitializerConfiguration.class);
  5. @Autowired
  6. private EurekaServerConfig eurekaServerConfig;
  7. private ServletContext servletContext;
  8. @Autowired
  9. private ApplicationContext applicationContext;
  10. @Autowired
  11. private EurekaServerBootstrap eurekaServerBootstrap;
  12. private boolean running;
  13. private int order = 1;
  14. @Override
  15. public void setServletContext(ServletContext servletContext) {
  16. this.servletContext = servletContext;
  17. }
  18. @Override
  19. public void start() {
  20. new Thread(new Runnable() {
  21. @Override
  22. public void run() {
  23. try {
  24. // 初始化
  25. eurekaServerBootstrap.contextInitialized(EurekaServerInitializerConfiguration.this.servletContext);
  26. log.info("Started Eureka Server");
  27. // 发布相关事件
  28. publish(new EurekaRegistryAvailableEvent(getEurekaServerConfig()));
  29. EurekaServerInitializerConfiguration.this.running = true;
  30. publish(new EurekaServerStartedEvent(getEurekaServerConfig()));
  31. }
  32. catch (Exception ex) {
  33. // Help!
  34. log.error("Could not initialize Eureka servlet context", ex);
  35. }
  36. }
  37. }).start();
  38. }
  39. @Override
  40. public void stop() {
  41. this.running = false;
  42. eurekaServerBootstrap.contextDestroyed(this.servletContext);
  43. }
  44. // 省略。。。
  45. }

该类实现了SmartLifecycle接口,说明在spring容器启动时会调用实现类的start方法
看下初始化方法

  1. public void contextInitialized(ServletContext context) {
  2. try {
  3. // 初始化eureka环境
  4. initEurekaEnvironment();
  5. // 初始化eureka server上下文
  6. initEurekaServerContext();
  7. context.setAttribute(EurekaServerContext.class.getName(), this.serverContext);
  8. }
  9. catch (Throwable e) {
  10. log.error("Cannot bootstrap eureka server :", e);
  11. throw new RuntimeException("Cannot bootstrap eureka server :", e);
  12. }
  13. }

初始化eureka server上下文

  1. protected void initEurekaServerContext() throws Exception {
  2. // For backward compatibility
  3. JsonXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(),
  4. XStream.PRIORITY_VERY_HIGH);
  5. XmlXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(),
  6. XStream.PRIORITY_VERY_HIGH);
  7. if (isAws(this.applicationInfoManager.getInfo())) {
  8. this.awsBinder = new AwsBinderDelegate(this.eurekaServerConfig,
  9. this.eurekaClientConfig, this.registry, this.applicationInfoManager);
  10. this.awsBinder.start();
  11. }
  12. EurekaServerContextHolder.initialize(this.serverContext);
  13. log.info("Initialized server context");
  14. // 同步Eureka集群数据,从相邻的eureka节点复制注册表,registryCount是复制过来的实例数
  15. int registryCount = this.registry.syncUp();
  16. // 定期剔除租约过期实例的定时任务就是在这里开启的
  17. this.registry.openForTraffic(this.applicationInfoManager, registryCount);
  18. // Register all monitoring statistics.
  19. EurekaMonitors.registerAllStats();
  20. }

@ConditionalOnBean({Marker.class})
这里就看到前面@EnableEurekaServer注解的作用了,只有标注了该注解,该配置类才会执行,EurekaServer才会启动
@EnableConfigurationProperties({ EurekaDashboardProperties.class, InstanceRegistryProperties.class })
这个是引入两个类

  1. @ConfigurationProperties("eureka.dashboard")
  2. public class EurekaDashboardProperties {
  3. /** * 控制台默认路径 */
  4. private String path = "/";
  5. /** * 是否开启控制台,默认是开启 */
  6. private boolean enabled = true;
  7. // setter getter...
  8. }

EurekaDashboardProperties就是两个关于控制台的配置

  1. @ConfigurationProperties(PREFIX)
  2. public class InstanceRegistryProperties {
  3. public static final String PREFIX = "eureka.instance.registry";
  4. /* 期望的每分钟续约次数,默认是1 */
  5. @Value("${eureka.server.expectedNumberOfRenewsPerMin:1}") // for backwards compatibility
  6. private int expectedNumberOfRenewsPerMin = 1;
  7. /** 默认打开的通信数量,默认1 */
  8. @Value("${eureka.server.defaultOpenForTrafficCount:1}") // for backwards compatibility
  9. private int defaultOpenForTrafficCount = 1;
  10. // setter/getter...
  11. }

InstanceRegistryProperties就是关于服务注册的配置
@PropertySource(“classpath:/eureka/server.properties”)
在这里插入图片描述
只是一个配置

现在看看类中创建的几个bean
创建EurekaServer配置bean,包含了EurekaServer的默认属性配置

  1. @Configuration
  2. protected static class EurekaServerConfigBeanConfiguration {
  3. @Bean
  4. @ConditionalOnMissingBean
  5. public EurekaServerConfig eurekaServerConfig(EurekaClientConfig clientConfig) {
  6. EurekaServerConfigBean server = new EurekaServerConfigBean();
  7. // 是否注册到集群中的其它server上
  8. if (clientConfig.shouldRegisterWithEureka()) {
  9. // Set a sensible default if we are supposed to replicate
  10. server.setRegistrySyncRetries(5);
  11. }
  12. return server;
  13. }
  14. }

控制台的Controller

  1. @Bean
  2. @ConditionalOnProperty(prefix = "eureka.dashboard", name = "enabled", matchIfMissing = true)
  3. public EurekaController eurekaController() {
  4. return new EurekaController(this.applicationInfoManager);
  5. }

设置Eureka的序列化工具

  1. @Bean
  2. public ServerCodecs serverCodecs() {
  3. return new CloudServerCodecs(this.eurekaServerConfig);
  4. }

创建EurekaServerBootstrap,上面初始化时用到该类

  1. @Bean
  2. public EurekaServerBootstrap eurekaServerBootstrap(PeerAwareInstanceRegistry registry,
  3. EurekaServerContext serverContext) {
  4. return new EurekaServerBootstrap(this.applicationInfoManager,
  5. this.eurekaClientConfig, this.eurekaServerConfig, registry,
  6. serverContext);
  7. }

创建jersey相关类,注册一个过滤器,跟接收客户端请求有关

  1. @Bean
  2. public FilterRegistrationBean jerseyFilterRegistration(
  3. javax.ws.rs.core.Application eurekaJerseyApp) {
  4. FilterRegistrationBean bean = new FilterRegistrationBean();
  5. // 设置过滤器
  6. bean.setFilter(new ServletContainer(eurekaJerseyApp));
  7. bean.setOrder(Ordered.LOWEST_PRECEDENCE);
  8. // 设置拦截路径,这里是/eureka/*
  9. bean.setUrlPatterns(
  10. Collections.singletonList(EurekaConstants.DEFAULT_PREFIX + "/*"));
  11. return bean;
  12. }
  13. @Bean
  14. public javax.ws.rs.core.Application jerseyApplication(Environment environment,
  15. ResourceLoader resourceLoader) {
  16. ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(
  17. false, environment);
  18. // Filter to include only classes that have a particular annotation.
  19. //
  20. provider.addIncludeFilter(new AnnotationTypeFilter(Path.class));
  21. provider.addIncludeFilter(new AnnotationTypeFilter(Provider.class));
  22. // Find classes in Eureka packages (or subpackages)
  23. //
  24. Set<Class<?>> classes = new HashSet<>();
  25. for (String basePackage : EUREKA_PACKAGES) {
  26. Set<BeanDefinition> beans = provider.findCandidateComponents(basePackage);
  27. for (BeanDefinition bd : beans) {
  28. Class<?> cls = ClassUtils.resolveClassName(bd.getBeanClassName(),
  29. resourceLoader.getClassLoader());
  30. classes.add(cls);
  31. }
  32. }
  33. // Construct the Jersey ResourceConfig
  34. //
  35. Map<String, Object> propsAndFeatures = new HashMap<>();
  36. propsAndFeatures.put(
  37. // Skip static content used by the webapp
  38. ServletContainer.PROPERTY_WEB_PAGE_CONTENT_REGEX,
  39. EurekaConstants.DEFAULT_PREFIX + "/(fonts|images|css|js)/.*");
  40. DefaultResourceConfig rc = new DefaultResourceConfig(classes);
  41. rc.setPropertiesAndFeatures(propsAndFeatures);
  42. return rc;
  43. }

jerseyApplication 方法,在容器中存放了一个jerseyApplication对象,jerseyApplication()方法里的东西和Spring源码里扫描@Component逻辑类似,扫描@Path和@Provider标签,然后封装成beandefinition,封装到Application的set容器里。通过filter过滤器来过滤url进行映射到对象的Controller

发表评论

表情:
评论列表 (有 0 条评论,295人围观)

还没有评论,来说两句吧...

相关阅读