spring boot 源码解析57-actuator组件:info背后的密码(全网独家)

解析

我们平常访问/info时会返回一些自定义的信息,一般人只知道在application.properties中配置info.author=herry 开头的配置,这样就可以在访问/info时,就会返回author: “herry”,但是如下的返回值是如何返回的,很多人就不会了

{
author: "herry",
git: {
commit: {
time: 1515694386000,
id: "自定义的commit.id.abbrev"
},
branch: "主干"
},
build: {
version: "0.0.1-SNAPSHOT",
artifact: "demo",
description: "Demo project for Spring Boot",
group: "com.example",
time: 1515694386000
}
}

InfoEndpoint的解析在spring boot 源码解析23-actuate使用及EndPoint解析中有介绍,InfoContributor最终是通过InfoEndpoint来调用的.

同时, InfoEndpoint向EndpointHandlerMapping注册的方式是通过EndpointMvcAdapter的方式来完成的,关于这点,可以看spring boot 源码解析55-spring boot actuator HandlerMapping全网独家揭秘

解析

关于这部分的类图如下:

《spring boot 源码解析57-actuator组件:info背后的密码(全网独家)》

InfoContributor

InfoContributor–> 添加 应用详情.代码如下:

public interface InfoContributor {

    // 向Info.Builder中添加信息
    void contribute(Info.Builder builder);

}

Info

很简单的一个封装类,使用了建造者模式

代码如下:

@JsonInclude(Include.NON_EMPTY)
public final class Info {

    private final Map<String, Object> details;

    private Info(Builder builder) {
        LinkedHashMap<String, Object> content = new LinkedHashMap<String, Object>();
        content.putAll(builder.content);
        this.details = Collections.unmodifiableMap(content);
    }

    @JsonAnyGetter
    public Map<String, Object> getDetails() {
        return this.details;
    }

    public Object get(String id) {
        return this.details.get(id);
    }

    @SuppressWarnings("unchecked")
    public <T> T get(String id, Class<T> type) {
        Object value = get(id);
        if (value != null && type != null && !type.isInstance(value)) {
            throw new IllegalStateException("Info entry is not of required type ["
                    + type.getName() + "]: " + value);
        }
        return (T) value;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        }
        if (obj != null && obj instanceof Info) {
            Info other = (Info) obj;
            return this.details.equals(other.details);
        }
        return false;
    }

    @Override
    public int hashCode() {
        return this.details.hashCode();
    }

    @Override
    public String toString() {
        return getDetails().toString();
    }


    public static class Builder {

        private final Map<String, Object> content;

        public Builder() {
            this.content = new LinkedHashMap<String, Object>();
        }

        public Builder withDetail(String key, Object value) {
            this.content.put(key, value);
            return this;
        }

        public Builder withDetails(Map<String, Object> details) {
            this.content.putAll(details);
            return this;
        }

        public Info build() {
            return new Info(this);
        }

    }

}

EnvironmentInfoContributor

EnvironmentInfoContributor–> 一个提供所有environment 属性中前缀为info的InfoContributor.

代码如下:

public class EnvironmentInfoContributor implements InfoContributor {

    private final PropertySourcesBinder binder;

    public EnvironmentInfoContributor(ConfigurableEnvironment environment) {
        this.binder = new PropertySourcesBinder(environment);
    }

    @Override
    public void contribute(Info.Builder builder) {
        // 通过PropertySourcesBinder 将info为前缀的环境变量抽取出来
        builder.withDetails(this.binder.extractAll("info"));
    }

}

MapInfoContributor

代码如下:

public class MapInfoContributor implements InfoContributor {

    private final Map<String, Object> info;

    public MapInfoContributor(Map<String, Object> info) {
        this.info = new LinkedHashMap<String, Object>(info);
    }

    @Override
    public void contribute(Info.Builder builder) {
        builder.withDetails(this.info);
    }

}

该类没有自动装配

SimpleInfoContributor

代码如下:

public class SimpleInfoContributor implements InfoContributor {

    private final String prefix;

    private final Object detail;

    public SimpleInfoContributor(String prefix, Object detail) {
        Assert.notNull(prefix, "Prefix must not be null");
        this.prefix = prefix;
        this.detail = detail;
    }

    @Override
    public void contribute(Info.Builder builder) {
        if (this.detail != null) {
            builder.withDetail(this.prefix, this.detail);
        }
    }

该类没有自动装配

InfoPropertiesInfoContributor

InfoPropertiesInfoContributor –> 一个暴露InfoProperties的InfoContributor.其泛型参数为T extends InfoProperties

  1. 字段,构造器如下:

    private final T properties;
    
    // 暴露的模式
    private final Mode mode;
    
    protected InfoPropertiesInfoContributor(T properties, Mode mode) {
        this.properties = properties;
        this.mode = mode;
    }

    Mode是1个枚举,代码如下:

    public enum Mode {
    
        // 暴露所有的信息
        FULL,
    
        // 只暴露预设的信息
        SIMPLE
    
    }
  2. 其声明了如下几个方法:

    1. generateContent –> 抽取出内容为info endpoint 使用.代码如下:

      protected Map<String, Object> generateContent() {
          // 1. 根据模式的不同暴露出所有的数据
          Map<String, Object> content = extractContent(toPropertySource());
          // 2. 默认空实现,子类可复写
          postProcessContent(content);
          return content;
      }
      1. 根据模式的不同暴露出所有的数据.

        toPropertySource方法实现如下:

        protected PropertySource<?> toPropertySource() {
            // 如果模式为FULL,则返回所有的数据,否则,只暴露预设的信息
            if (this.mode.equals(Mode.FULL)) {
                return this.properties.toPropertySource();
            }
            return toSimplePropertySource();
        }
        1. 如果模式为FULL,则返回所有的数据,否则,只暴露预设的信息
        2. 返回PropertySource–>SIMPLE 模式,抽象方法,子类实现.代码如下:

          protected abstract PropertySource<?> toSimplePropertySource();

        extractContent代码如下:

        protected Map<String, Object> extractContent(PropertySource<?> propertySource) {
            return new PropertySourcesBinder(propertySource).extractAll("");
        }
      2. 默认空实现,子类可复写.代码如下:

        protected void postProcessContent(Map<String, Object> content) {
        }
    2. copyIfSet –> 如果properties中有配置key的话,则copy到target中.代码如下:

      protected void copyIfSet(Properties target, String key) {
          String value = this.properties.get(key);
          if (StringUtils.hasText(value)) {
              target.put(key, value);
          }
      }
    3. replaceValue –> 替换值.代码如下:

      protected void replaceValue(Map<String, Object> content, String key, Object value) {
          if (content.containsKey(key) && value != null) {
              content.put(key, value);
          }
      }
    4. getNestedMap –> 获得嵌套的map 如果map中有给定key的话,否则返回empty map.代码如下:

      protected Map<String, Object> getNestedMap(Map<String, Object> map, String key) {
          Object value = map.get(key);
          if (value == null) {
              return Collections.emptyMap();
          }
          return (Map<String, Object>) value;
      }

InfoProperties

InfoProperties实现了Iterable接口,其泛型为InfoProperties.Entry.Entry如下:

public final class Entry {

        private final String key;

        private final String value;

        private Entry(String key, String value) {
            this.key = key;
            this.value = value;
        }

        public String getKey() {
            return this.key;
        }

        public String getValue() {
            return this.value;
        }

}
  1. 字段构造器如下:

    private final Properties entries;
    
    public InfoProperties(Properties entries) {
        Assert.notNull(entries, "Entries must not be null");
        this.entries = copy(entries);
    }

    copy 方法如下:

    private Properties copy(Properties properties) {
        Properties copy = new Properties();
        copy.putAll(properties);
        return copy;
    }
  2. 其它方法实现如下:

    1. get,如下:

      public String get(String key) {
          return this.entries.getProperty(key);
      }
    2. getDate,如下:

      public Date getDate(String key) {
          String s = get(key);
          if (s != null) {
              try {
                  return new Date(Long.parseLong(s));
              }
              catch (NumberFormatException ex) {
                  // Not valid epoch time
              }
          }
          return null;
      }
    3. iterator,如下:

      public Iterator<Entry> iterator() {
          return new PropertiesIterator(this.entries);
      }

      PropertiesIterator 代码如下:

      private final class PropertiesIterator implements Iterator<Entry> {
      
          private final Iterator<Map.Entry<Object, Object>> iterator;
      
          private PropertiesIterator(Properties properties) {
              this.iterator = properties.entrySet().iterator();
          }
      
          @Override
          public boolean hasNext() {
              return this.iterator.hasNext();
          }
      
          @Override
          public Entry next() {
              Map.Entry<Object, Object> entry = this.iterator.next();
              return new Entry((String) entry.getKey(), (String) entry.getValue());
          }
      
          @Override
          public void remove() {
              throw new UnsupportedOperationException("InfoProperties are immutable.");
          }
      }
    4. toPropertySource,代码如下:

      public PropertySource<?> toPropertySource() {
          return new PropertiesPropertySource(getClass().getSimpleName(),
                  copy(this.entries));
      }

BuildProperties

BuildProperties–> 继承自InfoProperties,提供项目构建相关的信息

  1. 构造器如下:

    public BuildProperties(Properties entries) {
        super(processEntries(entries));
    }

    processEntries–>从给的Properties 将time所对应的值转换为时间戳的格式.代码如下:

    private static Properties processEntries(Properties properties) {
        coerceDate(properties, "time");
        return properties;
    }
    
    private static void coerceDate(Properties properties, String key) {
        String value = properties.getProperty(key);
        if (value != null) {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
            try {
                String updatedValue = String.valueOf(format.parse(value).getTime());
                properties.setProperty(key, updatedValue);
            }
            catch (ParseException ex) {
                // Ignore and store the original value
            }
        }
    }
  2. 其他方法,都是最终调用InfoProperties#get,如下:

    public String getGroup() {
        return get("group");
    }
    
    public String getArtifact() {
        return get("artifact");
    }
    
    public String getName() {
        return get("name");
    }
    
    public String getVersion() {
        return get("version");
    }
    
    public Date getTime() {
        return getDate("time");
    }

GitProperties

GitProperties–> 继承自InfoProperties,提供git相关的信息比如 commit id 和提交时间。

  1. 构造器如下:

    public GitProperties(Properties entries) {
        super(processEntries(entries));
    }

    processEntries–>将git.properties中的commit.time,build.time 转换为yyyy-MM-dd’T’HH:mm:ssZ 格式的数据.代码如下:

    private static Properties processEntries(Properties properties) {
        coercePropertyToEpoch(properties, "commit.time");
        coercePropertyToEpoch(properties, "build.time");
        return properties;
    }

    coercePropertyToEpoch代码如下:

    private static void coercePropertyToEpoch(Properties properties, String key) {
        String value = properties.getProperty(key);
        if (value != null) {
            properties.setProperty(key, coerceToEpoch(value));
        }
    }

    coerceToEpoch –> 尝试将给定的字符串转换为纪元时间.Git属性信息被指定为秒或使用yyyy-MM-dd’T’HH:mm:ssZ 格式的数据.代码如下:

    private static String coerceToEpoch(String s) {
        Long epoch = parseEpochSecond(s);
        if (epoch != null) {
            return String.valueOf(epoch);
        }
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
        try {
            return String.valueOf(format.parse(s).getTime());
        }
        catch (ParseException ex) {
            return s;
        }
    }
    
    private static Long parseEpochSecond(String s) {
        try {
            return Long.parseLong(s) * 1000;
        }
        catch (NumberFormatException ex) {
            return null;
        }
    }
  2. 其他方法,都是最终调用InfoProperties#get,如下:

    public String getBranch() {
        return get("branch");
    }
    
    
    public String getCommitId() {
        return get("commit.id");
    }
    
    
    public String getShortCommitId() {
        // 1. 获得commit.id.abbrev
        String shortId = get("commit.id.abbrev");
        if (shortId != null) {
            return shortId;
        }
        // 2.commit.id,如果不等于null并且id长度大于7,则截取前7位
        String id = getCommitId();
        if (id == null) {
            return null;
        }
        return (id.length() > 7 ? id.substring(0, 7) : id);
    }
    
    
    public Date getCommitTime() {
        return getDate("commit.time");
    }

BuildInfoContributor

BuildInfoContributor–>继承自InfoPropertiesInfoContributor,将BuildProperties暴露出去

  1. 构造器如下:

    public BuildInfoContributor(BuildProperties properties) {
        super(properties, Mode.FULL);
    }
  2. 方法实现如下:

    1. contribute,代码如下:

      public void contribute(Info.Builder builder) {
          builder.withDetail("build", generateContent());
      }

      由于BuildInfoContributor默认的Mode为FULL,因此该方法最终会将BuildProperties中的所有数据暴露出去,其key为build

    2. toSimplePropertySource–> 当BuildInfoContributor的Mode为SIMPLE时调用,一般不会调用该方法代码如下:

      protected PropertySource<?> toSimplePropertySource() {
          Properties props = new Properties();
          // 1. 默认读取META-INF/build-info.properties中的build.group
          copyIfSet(props, "group");
          copyIfSet(props, "artifact");
          copyIfSet(props, "name");
          copyIfSet(props, "version");
          copyIfSet(props, "time");
          return new PropertiesPropertySource("build", props);
      }
      1. 将META-INF/build-info.properties中的build.group, build.artifact, build.name, build.version, build.time 复制到Properties中
      2. 实例化PropertiesPropertySource,名字为build
    3. postProcessContent–> 将build.time 转换为time.代码如下:

      protected void postProcessContent(Map<String, Object> content) {
          // 将build.time 转换为time
          replaceValue(content, "time", getProperties().getTime());
      }

GitInfoContributor

GitInfoContributor–>继承自InfoPropertiesInfoContributor,将GitProperties暴露出去

  1. 构造器如下:

    public GitInfoContributor(GitProperties properties, Mode mode) {
        // 默认是SIMPLE
        super(properties, mode);
    }
    
    public GitInfoContributor(GitProperties properties) {
        this(properties, Mode.SIMPLE);
    }
  2. 方法实现如下:

    1. contribute–>当Mode为full时调用,由于默认是SIMPLE,因此该方法一般不会调用.代码如下:

      public void contribute(Info.Builder builder) {
          builder.withDetail("git", generateContent());
      }
    2. toSimplePropertySource–> 默认调用,代码如下:

      protected PropertySource<?> toSimplePropertySource() {
          Properties props = new Properties();
          // 1. 从git.properties中获得branch
          copyIfSet(props, "branch");
          // 2. 从git.properties中获得commit.id.abbrev
          String commitId = getProperties().getShortCommitId();
          if (commitId != null) {
              props.put("commit.id", commitId);
          }
          // 2. 从git.properties中获得commit.time
          copyIfSet(props, "commit.time");
          return new PropertiesPropertySource("git", props);
      }
      1. 从git.properties中获得branch,复制到props中
      2. 从git.properties中获得commit.id.abbrev,复制到props中
      3. 从git.properties中获得commit.time,复制到props中
      4. 实例化 PropertiesPropertySource,名字为git
    3. postProcessContent,代码如下:

      protected void postProcessContent(Map<String, Object> content) {
          // 1. 获得commit所对应的map中time所对应的值,将其转换为Date,然后将其进行替换
          replaceValue(getNestedMap(content, "commit"), "time", getProperties().getCommitTime());
          // 2. 获得build所对应的map中time所对应的值,将其转换为Date,然后将其进行替换
          replaceValue(getNestedMap(content, "build"), "time", getProperties().getDate("build.time"));
      }
      1. 获得commit所对应的map中time所对应的值,将其转换为Date,然后将其进行替换
      2. 获得build所对应的map中time所对应的值,将其转换为Date,然后将其进行替换

自动装配

InfoProperties

InfoProperties相关的类–>GitProperties,BuildProperties的自动装配是在ProjectInfoAutoConfiguration中, ProjectInfoAutoConfiguration声明了如下注解:

@Configuration
@EnableConfigurationProperties(ProjectInfoProperties.class)

ProjectInfoProperties代码如下:

@ConfigurationProperties(prefix = "spring.info")
public class ProjectInfoProperties {

    // 构建的具体的信息,默认加载路径为META-INF/build-info.properties
    private final Build build = new Build();

    // git具体的信息,默认加载路径为classpath:git.properties
    private final Git git = new Git();

    public Build getBuild() {
        return this.build;
    }

    public Git getGit() {
        return this.git;
    }

    /** * Make sure that the "spring.git.properties" legacy key is used by default. * @param defaultGitLocation the default git location to use */
    @Autowired
    void setDefaultGitLocation(
            @Value("${spring.git.properties:classpath:git.properties}") Resource defaultGitLocation) {
        getGit().setLocation(defaultGitLocation);
    }

    /** * Build specific info properties. */
    public static class Build {

        /** * Location of the generated build-info.properties file. */
        private Resource location = new ClassPathResource(
                "META-INF/build-info.properties");

        public Resource getLocation() {
            return this.location;
        }

        public void setLocation(Resource location) {
            this.location = location;
        }

    }

    /** * Git specific info properties. */
    public static class Git {

        /** * Location of the generated git.properties file. */
        private Resource location;

        public Resource getLocation() {
            return this.location;
        }

        public void setLocation(Resource location) {
            this.location = location;
        }

    }

}

其中Build的默认配置为META-INF/build-info.properties,Git的默认配置为classpath:git.properties

可通过如下属性来配置:

spring.info.build.location=classpath:META-INF/build-info.properties # Location of the generated build-info.properties file.
spring.info.git.location=classpath:git.properties # Location of the generated git.properties file.

在ProjectInfoAutoConfiguration中声明2个@Bean方法:

  1. buildProperties,代码如下:

    @ConditionalOnResource(resources = "${spring.info.build.location:classpath:META-INF/build-info.properties}")
    @ConditionalOnMissingBean
    @Bean
    public BuildProperties buildProperties() throws Exception {
        return new BuildProperties(
                loadFrom(this.properties.getBuild().getLocation(), "build"));
    }
    • @ConditionalOnResource(resources = “${spring.info.build.location:classpath:META-INF/build-info.properties}”)–>满足如下条件时生效:

      1. 如果spring.info.build.location配置了,则如果spring.info.build.location:classpath配置路径下存在资源文件,则返回true
      2. 如果spring.info.build.location没配置,则如果在classpath:META-INF/build-info.properties中存在的话,则生效
    • @ConditionalOnMissingBean –> BeanFactory中不存在BuildProperties类型的bean时生效

    其创建BuildProperties时调用了loadFrom方法,来加载配置的文件,并且将文件中不是build开头的配置进行过滤.

    loadFrom–> 方法只加载给定location的Properties文件中以prefix开头的配置.如下:

    protected Properties loadFrom(Resource location, String prefix) throws IOException {
        String p = prefix.endsWith(".") ? prefix : prefix + ".";
        Properties source = PropertiesLoaderUtils.loadProperties(location);
        Properties target = new Properties();
        for (String key : source.stringPropertyNames()) {
            if (key.startsWith(p)) {
                target.put(key.substring(p.length()), source.get(key));
            }
        }
        return target;
    }
  2. gitProperties,代码如下:

    @Conditional(GitResourceAvailableCondition.class)
    @ConditionalOnMissingBean
    @Bean
    public GitProperties gitProperties() throws Exception {
        return new GitProperties(loadFrom(this.properties.getGit().getLocation(), "git"));
    }
    • @ConditionalOnMissingBean–> BeanFactory中不存在GitProperties类型的bean时生效
    • @Conditional(GitResourceAvailableCondition.class) –> 如果以下路径中任意1个存在则生效:

      1. spring.info.git.location配置的路径
      2. spring.git.properties配置的路径
      3. classpath:git.properties配置的路径

    其创建GitProperties时调用了loadFrom方法,来加载配置的文件,并且将文件中不是git开头的配置进行过滤.

InfoContributor

InfoContributor相关的子类的自动装配在InfoContributorAutoConfiguration中进行了配置,其声明了如下注解:

@Configuration
@AutoConfigureAfter(ProjectInfoAutoConfiguration.class)
@AutoConfigureBefore(EndpointAutoConfiguration.class)
@EnableConfigurationProperties(InfoContributorProperties.class)

InfoContributorProperties代码如下:

@ConfigurationProperties("management.info")
public class InfoContributorProperties {

    private final Git git = new Git();

    public Git getGit() {
        return this.git;
    }

    public static class Git {

        /** * Mode to use to expose git information. */
        private GitInfoContributor.Mode mode = GitInfoContributor.Mode.SIMPLE;

        public GitInfoContributor.Mode getMode() {
            return this.mode;
        }

        public void setMode(GitInfoContributor.Mode mode) {
            this.mode = mode;
        }

    }

}

因此可以通过management.info.git.mode,来配置GitInfoContributor的输出模式,默认为SIMPLE

InfoContributorAutoConfiguration声明了3个bean方法:

  1. envInfoContributor,代码如下:

    @Bean
    @ConditionalOnEnabledInfoContributor("env")
    @Order(DEFAULT_ORDER)
    public EnvironmentInfoContributor envInfoContributor(
            ConfigurableEnvironment environment) {
        return new EnvironmentInfoContributor(environment);
    }
    • @Bean –> 注册1个id为envInfoContributor,类型为EnvironmentInfoContributor的bean
    • @ConditionalOnEnabledInfoContributor(“env”) –> 如果配置有management.info.env .enabled= true或者配置有management.info.enabled = true. 或者没有配置时默认匹配
  2. gitInfoContributor,代码如下:

    @Bean
    @ConditionalOnEnabledInfoContributor("git")
    @ConditionalOnSingleCandidate(GitProperties.class)
    @ConditionalOnMissingBean
    @Order(DEFAULT_ORDER)
    public GitInfoContributor gitInfoContributor(GitProperties gitProperties) {
        return new GitInfoContributor(gitProperties, this.properties.getGit().getMode());
    }
    • @Bean –> 注册1个id为gitInfoContributor,类型为GitInfoContributor的bean
    • @ConditionalOnEnabledInfoContributor(“git”) –> 如果配置有management.info.git.enabled= true或者配置有management.info.enabled = true. 或者没有配置时默认匹配
    • @ConditionalOnMissingBean–> BeanFactory中不存在类型为GitInfoContributor的bean时生效
    • @ConditionalOnSingleCandidate(GitProperties.class) –> 如果BeanFactory中只存在1个GitProperties类型的bean或者存在多个,但是存在1个被指定为Primary的bean时生效
  3. buildInfoContributor,代码如下:

    @Bean
    @ConditionalOnEnabledInfoContributor("build")
    @ConditionalOnSingleCandidate(BuildProperties.class)
    @Order(DEFAULT_ORDER)
    public InfoContributor buildInfoContributor(BuildProperties buildProperties) {
        return new BuildInfoContributor(buildProperties);
    }
    • @Bean –> 注册1个id为buildInfoContributor,类型为InfoContributor的bean
    • @ConditionalOnEnabledInfoContributor(“build”) –> 如果配置有management.info.build.enabled= true或者配置有management.info.enabled = true. 或者没有配置时默认匹配

实战

  1. 要先在spring boot的项目中激活 BuildInfoContributor的配置,需要在META-INF目录下存在build-info.properties,我们可以spring-boot-maven-plugin来完成,其有5个goal:

    1. spring-boot:repackage,默认goal。在mvn package之后,再次打包可执行的jar/war,同时保留mvn package生成的jar/war为.origin
    2. spring-boot:run,运行Spring Boot应用
    3. spring-boot:start,在mvn integration-test阶段,进行Spring Boot应用生命周期的管理
    4. spring-boot:stop,在mvn integration-test阶段,进行Spring Boot应用生命周期的管理
    5. spring-boot:build-info,生成Actuator使用的构建信息文件build-info.properties.默认输出路径为${project.build.outputDirectory}/META-INF/build-info.properties

    因此,我们可以修改pom文件为如下:

    <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>build-info</goal>
                        </goals>
                    </execution>
                </executions>
    </plugin>

    此时我们执行mvn: clean install ,就可以发现在最终生成的jar包中存在build-info.properties,如下:

    《spring boot 源码解析57-actuator组件:info背后的密码(全网独家)》

  2. 同样,要激活GitInfoContributor,我们可以在pom文件中加入如下配置:

    <plugin>
                <groupId>pl.project13.maven</groupId>
                <artifactId>git-commit-id-plugin</artifactId>
                <version>2.1.15</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>revision</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <dotGitDirectory>${project.basedir}/.git</dotGitDirectory>
                </configuration>
    </plugin>

    执行mvn:git-commit-id:revision,就可以发现在最终生成的jar包中存在build-info.properties,如下:

    《spring boot 源码解析57-actuator组件:info背后的密码(全网独家)》

  3. 此时,我们启动应用后,访问如下链接http://127.0.0.1:8080/info,就可以发现其返回内容如下:

    { git: { commit: { time: 1517484030000, id: "8973672" },
        branch: "master"
        },
    build: { version: "0.0.1-SNAPSHOT", artifact: "spring-boot-analysis", name: "spring-boot-analysis", group: "com.roncoo", time: 1517484169000 }
    }

    当然我们可以配置management.info.git.mode=FULL,来输出更多的信息,试一下吧

参考链接:

spring-boot:build-info

Spring Boot的Maven插件Spring Boot Maven plugin详解

Maven插件之git-commit-id-plugin

    原文作者:Spring Boot
    原文地址: https://blog.csdn.net/qq_26000415/article/details/79234812
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞