`
357029540
  • 浏览: 726619 次
  • 性别: Icon_minigender_1
  • 来自: 重庆
社区版块
存档分类
最新评论
阅读更多

了解完spring.cloud.config.client模块的代码,现在来了解下spring.cloud.config.monitor模块的代码。通过spring.factories启动文件可用看到只配置了一个自动配置类EnvironmentMonitorAutoConfiguration,我我们来看下这个类。

 进入到EnvironmentMonitorAutoConfiguration类,通过头部的注解可以了解到它是一个配置类,并且只能运行在WebApplication环境,然后通过注解@Import引入了FileMonitorConfiguration类。

 进入到FileMonitorConfiguration类,可以看到它实现了SmartLifecycle和ResourceLoaderAware接口,从这2个接口中可以看到一个是用于生命周期的管理,一个是用于资源文件的加载。通过FileMonitorConfiguration这个类的注解可以了解到它定义了一个定时任务。

 首先看看FileMonitorConfiguration类实现的SmartLifecycle接口的start()方法

public synchronized void start() {
   if (!this.running) {
      this.directory = getFileRepo();
      if (this.directory != null && !this.directory.isEmpty()) {
         log.info("Monitoring for local config changes: " + this.directory);
         try {
            this.watcher = FileSystems.getDefault().newWatchService();
            for (Path path : this.directory) {
               walkDirectory(path);
            }
         }
         catch (IOException e) {
         }
      }
      else {
         log.info("Not monitoring for local config changes");
      }
      this.running = true;
   }
}

 在初始化的时候字段running状态为false的时候通过getFileRepo()方法获取Set集合的文件路径

private Set<Path> getFileRepo() {
   if (this.scmRepository != null) {
      try {

         Resource resource = this.resourceLoader.getResource(this.scmRepository.getUri());
         if (resource instanceof FileSystemResource) {
            return Collections.singleton(Paths.get(resource.getURI()));
         }
      }
      catch (IOException e) {
         log.error("Cannot resolve URI for path: " + this.scmRepository.getUri());
      }
   }
   if (this.nativeEnvironmentRepository != null) {
      Set<Path> paths = new LinkedHashSet<>();
      for (String path : this.nativeEnvironmentRepository.getSearchLocations()) {
         Resource resource = this.resourceLoader.getResource(path);
         if (resource.exists()) {
            try {
               paths.add(Paths.get(resource.getURI()));
            }
            catch (Exception e) {
               log.error("Cannot resolve URI for path: " + path);
            }
         }
      }
      return paths;
   }
   return null;
}

在getFileRepo()方法中,它是通过ResourceLoader去加载配置的服务地址,返回获取的Resource信息,如果本地环境nativeEnvironmentRepository不为空,则去本地环境加载路径值。获取到path路径的Set集合后通过 FileSystems.getDefault().newWatchService()定义一个WatchService的监控类,然后循环path路径的Set集合,通过walkDirectory()方法来添加对文件的监控信息,git的文件不需要。

在看EnvironmentMonitorAutoConfiguration类,它定义了一个PropertyPathEndpoint的bean,这个bean引入了Bus模块的相关配置,因为这个类要配合bus模块来应用,我们进入到PropertyPathEndpoint类,可以看到它是一个RestController的API类,可以通过spring.cloud.config.monitor.endpoint.path自定义访问路径,然后加上monitor路径进行访问,同时它实现了ApplicationEventPublisherAware接口用于事件发布,我们看下它的2个path路径,都是通过POST方式访问的,但是notifyByForm()方法定义了consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE的访问条件,最终也是调用notifyByPath()方法,我们看下该方法

@RequestMapping(method = RequestMethod.POST)
public Set<String> notifyByPath(@RequestHeader HttpHeaders headers,
      @RequestBody Map<String, Object> request) {
   PropertyPathNotification notification = this.extractor.extract(headers, request);
   if (notification != null) {

      Set<String> services = new LinkedHashSet<>();

      for (String path : notification.getPaths()) {
         services.addAll(guessServiceName(path));
      }
      if (this.applicationEventPublisher != null) {
         for (String service : services) {
            log.info("Refresh for: " + service);
            this.applicationEventPublisher
                  .publishEvent(new RefreshRemoteApplicationEvent(this,
                        this.busId, service));
         }
         return services;
      }

   }
   return Collections.emptySet();
}

 在notifyByPath()方法中,通过PropertyPathNotificationExtractor类的具体实现类去实现extract()方法,我们主要看下它的实现类BasePropertyPathNotificationExtractor类,这个类主要是用于git相关的解析,我们看下extract()方法

public PropertyPathNotification extract(MultiValueMap<String, String> headers,
        Map<String, Object> request) {
    if (requestBelongsToGitRepoManager(headers)) {
        if (request.get("commits") instanceof Collection) {
            Set<String> paths = new HashSet<>();
            @SuppressWarnings("unchecked")
            Collection<Map<String, Object>> commits = (Collection<Map<String, Object>>) request
                    .get("commits");
            addPaths( paths, commits );
            if (!paths.isEmpty()) {
                return new PropertyPathNotification(paths.toArray(new String[0]));
            }
        }
    }
    return null;
}

 在extract()方法中,首先是通过requestBelongsToGitRepoManager()方法判断是否包含特定的推送信息,这里我们以GithubPropertyPathNotificationExtractor为例

protected boolean requestBelongsToGitRepoManager(MultiValueMap<String, String> headers) {
    return "push".equals(headers.getFirst("X-Github-Event"));
}

 通过requestBelongsToGitRepoManager()方法判断头部中的X-Github-Event是否是push事件,然后获取request集合中的commits信息,将获取到的文件改变的推送路径加载到paths集合中,返回PropertyPathNotification对象。

   获取到PropertyPathNotification对象后,在PropertyPathEndpoint类的notifyByPath()方法中定义了一个services的LinkedHashSet集合,该services用来添加在PropertyPathNotification对象中获取到的path路径,我们看下guessServiceName()方法

private Set<String> guessServiceName(String path) {
   Set<String> services = new LinkedHashSet<>();
   if (path != null) {
      String stem = StringUtils
            .stripFilenameExtension(StringUtils.getFilename(StringUtils.cleanPath(path)));
      // TODO: correlate with service registry
      int index = stem.indexOf("-");
      while (index >= 0) {
         String name = stem.substring(0, index);
         String profile = stem.substring(index + 1);
         if ("application".equals(name)) {
            services.add("*:" + profile);
         }
         else if (!name.startsWith("application")) {
            services.add(name + ":" + profile);
         }
         index = stem.indexOf("-", index + 1);
      }
      String name = stem;
      if ("application".equals(name)) {
         services.add("*");
      }
      else if (!name.startsWith("application")) {
         services.add(name);
      }
   }
   return services;
}

在guessServiceName()方法中,首先对路径进行了消除获取到了字符串为stem的文件后缀的名字,然后通过一系列的判断对文件进行加*操作,用于事件发布的需要。退出guessServiceName()方法后,在PropertyPathEndpoint类的notifyByPath()方法中对services进行了事件的发布通过RefreshRemoteApplicationEvent事件。

  介绍完PropertyPathEndpoint类,我们在回头看看EnvironmentMonitorAutoConfiguration类中定义的static类PropertyPathNotificationExtractorConfiguration,在该类中定义了一系列的PropertyPathNotificationExtractor接口实现类,在这些类上面都定义了prefix的配置路径,默认上是都加载,具体可以参考前面提到的GithubPropertyPathNotificationExtractor类,这里不在一一说明。 

0
0
分享到:
评论

相关推荐

    SpringCloud教程

    史上最简单的SpringCloud教程 | 第五篇: 路由网关(zuul) 史上最简单的SpringCloud教程 | 第六篇: 分布式配置中心(Spring Cloud Config) 史上最简单的SpringCloud教程 | 第七篇: 高可用的分布式配置中心(Spring Cloud...

    springCloud

    断路器示意图 SpringCloud Netflix实现了断路器库的名字叫Hystrix. 在微服务架构下,通常会有多个层次的服务调用. 下面是微服架构下, 浏览器端通过API访问后台微服务的一个示意图: hystrix 1 一个微服务的超时...

    SpringCloudLearning_forezp.tar.gz

    史上最简单的SpringCloud教程 | 第五篇: 路由网关(zuul)(Finchley版本) 史上最简单的SpringCloud教程 | 第六篇: 分布式配置中心(Spring Cloud Config)(Finchley版本) 史上最简单的SpringCloud教程 | 第七篇: 高可用...

    SpringCloud配置中心Config过程解析

    主要介绍了SpringCloud配置中心Config过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    spring boot实战.pdf高清无水印

    2.1.2 Spring Boot项目构建过程解析 24 2.2 使用起步依赖 27 2.2.1 指定基于功能的依赖 28 2.2.2 覆盖起步依赖引入的传递依赖 29 2.3 使用自动配置 30 2.3.1 专注于应用程序功能 31 2.3.2 运行应用程序...

Global site tag (gtag.js) - Google Analytics