Display build timestamp in Spring Boot actuator info endpoint - java

I am using the Spring Boot actuator to get my application's info.
I have added the Spring Boot actuator dependency in my pom.xml, and added below lines in my property file:
info:
app:
name: #project.name#
description: #project.description#
version: #project.version#
I get the values: name, description and version of my project from pom.xml. I also want to get build time and display it on the /info endpoint.
Any suggestions?
Should I also Change my pom.xml file for it?
I tried using :
info.app.build-time=#build-time#
But this doesnt work.
Thanks

You can define a timestamp Maven property in your pom.xml like so:
<properties>
<timestamp>${maven.build.timestamp}</timestamp>
<maven.build.timestamp.format>yyyy-MM-dd-HH:mm</maven.build.timestamp.format>
</properties>
And then reference it using the #...# convention like so:
info:
app:
timestamp: #timestamp#

Spring Boot (1.5.10.RELEASE or 2.0.0.RELEASE) supports this using the actuator-starter with the help of some simple gradle/maven adoption now.
You can add git commit information as well as build information and customize them to some extend.

Related

Why doesn't Spring Cloud use bootstrap.yml by default anymore?

This is my Spring Cloud test project. As the java version is 1.8, I try to build the cloud project with some new version.
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<mysql.version>8.0.30</mysql.version>
<mybatis.version>3.0.0</mybatis.version>
<mybatis-plus.version>3.5.2</mybatis-plus.version>
<spring-boot.version>2.6.11</spring-boot.version>
<spring-cloud.version>2021.0.4</spring-cloud.version>
<spring-cloud-alibaba.version>2021.0.4.0</spring-cloud-alibaba.version>
<alibaba.nacos.version>2.0.4</alibaba.nacos.version>
<freemarker.version>2.3.31</freemarker.version>
<swagger.version>1.6.2</swagger.version>
<lombok.version>1.18.8</lombok.version>
<openfeign.version>3.1.5</openfeign.version>
<loadbalance.version>3.1.4</loadbalance.version>
</properties>
enter image description here
https://github.com/Autrui/cloud_test
Then I get the problem. In order and user module, I use bootstrap.yml to config name and nacos, it actually worked. But in gateway module, at first, I set the port 10010 in bootstrap.yml, but the gateway still runs at port 8080. The configuration in application.yml worked.
Then I Google and found that Spring Boot disabled the bootstrap.yml after 2.4.0. Then I have three problems:
If the bootstrap is actually be abandoned, why my order and user modules can work as usual?
I find we can add the bootstrap dependency in pom, then bootstrap will be loaded again, but I think this is not a elegant way to program.
config:
import:
- optional: nacos:order-dev.yaml
- nacos: order-dev.yaml
I try to use spring.config.import, but IDEA shows Cannot resolve property 'optional' in java.lang.String. How can I replace bootstrap in my project?
Why Spring disabled the bootstrap? I didn't find the reason also don't know why.

Configuring Spring Boot project with multiple Maven modules

I have a web project with following structure:
app
pom.xml
–modules:
app-api (contains only OpenAPI documentation used to generate REST endpoints)
pom.xml
app-service (contains the actual business logic with services/controllers/etc)
pom.xml
I am trying to manually run SonarCloud.
I put the following settings in the parent pom.xml
<sonar.organization>company-account</sonar.organization>
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
<sonar.projectKey>project-name</sonar.projectKey>
All of the above are taken according to what the Sonar web portal is recommending.
I added the SONAR_TOKEN variable as well.
At the moment I am getting:
"Project ‘…’ can’t have 2 modules with the following key: …
I tried a bunch of other combinations, like putting the maven properties in the service submodule.
It either does not recognize the project or gives me a stackoverflow error.
I tried passing the project key as a parameter:
mvn verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=the-project-key
It just gives another error:
Project not found. Please check the ‘sonar.projectKey’ and ‘sonar.organization’ properties, the ‘SONAR_TOKEN’ environment variable, or contact the project administrator
Do you have any idea what am I doing wrong?

Overriden application.yml in multi-module Spring Boot app

There is a Spring Boot 2 app with such a structure:
parent-module
module-1
src
main
java
resources
- application.yml
module-2
src
main
java
resources
- application.yml
Also, module-1 depends on module-2, specified in pom.xml dependencies section.
The problem is that when I specify some properties in module-2's application.yml - they are not visible in main module-1's components (via #Value annotation).
As was answered here seems like module-1's application.yml overrides module-2's application.yml. There is a workaround - if I use name application.yaml in module-2 everything works fine, but I'm going to add more modules and, finally, it's dirty hack.
What I'm doing wrong? Should such an hierarchy of property files specified somehow?
I will be happy to provide more details if it's needed.
Thank you!
Spring Boot is a runtime framework. I understand that your modules are not spring-boot applications by themselves (you can't make a dependency on a spring boot application packaged with spring boot maven plugin, because it produces an artifact that is not really a JAR from the Java's standpoint although it does have *.jar extension).
If so, they're probably regular jars. So you should have a "special" module that assembles the application. This special module lists both 'module1' and 'module2' in <dependency> section and should contain a definition of spring-boot-maven-plugin in its build section (assuming you're using maven). But if so you shouldn't really have more than one application.yml - it will be misleading. Instead, put the application.yml to the src/main/resources of that "special" module.
If you really have to for whatever reason work with multiple application.yaml files, make sure you've read this thread
I know, this is already a well-aged post.
I just came accross the same issue and the best solution I found was to import the module-specific configurations with the spring.config.import directive as described here.
In this case you still have your module specific configuration in property or yaml files within that specific module and do not have too much unwanted dependencies in your project setup.
application.yml is, as the name indicates, an application-level file, not a module-level file.
It is the build script that assembles the final application, e.g. the .war file, that needs to include a application.yml file, if any.
If modules need properties, and cannot rely on the defaults, e.g. using the : syntax in #Value("${prop.name:default}"), they need to provide a module-level property file using #PropertySource("classpath:/path/to/module-2.properties").
Note: By default, #PropertySource doesn't load YAML files (see official documentation), but Spring Boot can be enhanced to support it. See #PropertySource with YAML Files in Spring Boot | Bealdung.
Alternative: Have the application-level build script (the one building the .war file) merge multiple module-level build scripts into a unified application.yml file.

Spring boot - disable Liquibase at startup

I want to have Liquibase configured with my Spring Boot application, so I added dependencies to pom.xml and set the path to master.xml in application.properties. This works fine and Spring Boot runs Liquibase at startup. The problem is that now I want to run Liquibase manually, not at startup of application. Should I completely disable auto-configuration for Liquibase or can I use it and only disable running evaluations at startup?
The relevant property name has changed between Spring versions:
For Spring 4.x.x: the liquibase.enabled=false application property disables Liquibase.
For Spring 5.x.x: the spring.liquibase.enabled=false application property disables Liquibase.
P.S. And for Flyway:
Spring 4.x.x: flyway.enabled=false
Spring 5.x.x: spring.flyway.enabled=false
Add liquibase.enabled=false in your application.properties file
Reference
But if you don't want to use liquibase from application anymore, remove liquibase starter altogether from pom.
If you see on the LiquibaseProperties, there is a prefix like
prefix = "spring.liquibase"
So, My suggestion is to use
spring.liquibase.enabled=false
It solved my problem with spring boot 2.0.0.RC1
I faced an issue where I wasn't able to disable Liquibase from properties for some reason, so this is how I disabled Liquibase with #Bean annotation:
#Bean
public SpringLiquibase liquibase() {
SpringLiquibase liquibase = new SpringLiquibase();
liquibase.setShouldRun(false);
return liquibase;
}
There is one more programmatic approach.
#EnableAutoConfiguration(exclude = LiquibaseAutoConfiguration.class)
on Application main class
If you want to run Liquibase manually, you could use the liquibase maven plugin. Just add something like this to your pom.xml:
<plugin>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-maven-plugin</artifactId>
<version>${liquibase.version}</version>
<configuration>
<changeLogFile>src/main/liquibase/master.xml</changeLogFile>
<propertyFile>src/main/liquibase/liquibase.properties</propertyFile>
<promptOnNonLocalDatabase>false</promptOnNonLocalDatabase>
</configuration>
</plugin>
You can take a look at the plugin documentation for the configuration details.
And don't use the liquibase support from Spring Boot, as it is only meant to be used in runtime. Just remove the liquibase starter and/or any related dependencies as you'll only need the maven plugin.
You can use the spring.liquibase.enabled=true/false
Whilst the documented Spring Boot solution is spring.liquibase.enabled=false, it didn't work for me. To disable liquibase you can also use the following property:
liquibase.shouldRun=false
I passed this as a command line parameter when launching the Spring Boot jar
-Dliquibase.shouldRun=false
see https://docs.liquibase.com/parameters/should-run.html

Using Spring boot/cloud with Amazon AWS lambda does not inject values

I have an AWS lambda RequestHandler class which is invoked directly by AWS. Eventually I need to get it working with Spring Boot because I need it to be able to retrieve data from Spring Cloud configuration server.
The problem is that the code works if I run it locally from my own dev environment but fails to inject config values when deployed on AWS.
#Configuration
#EnableAutoConfiguration
#ComponentScan("my.package")
public class MyClass implements com.amazonaws.services.lambda.runtime.RequestHandler<I, O> {
public O handleRequest(I input, Context context) {
ApplicationContext applicationContext = new SpringApplicationBuilder()
.main(getClass())
.showBanner(false)
.web(false)
.sources(getClass())
.addCommandLineProperties(false)
.build()
.run();
log.info(applicationContext.getBean(SomeConfigClass.class).foo);
// prints cloud-injected value when running from local dev env
//
// prints "${path.to.value}" literal when running from AWS
// even though Spring Boot starts successfully without errors
}
}
#Configuration
public class SomeConfigClass {
#Value("${path.to.value}")
public String foo;
}
src/main/resources/bootstrap.yml:
spring:
application:
name: my_service
cloud:
config:
uri: http://my.server
failFast: true
profile: localdev
What have I tried:
using regular Spring MVC, but this doesn't have integration with #Value injection/Spring cloud.
using #PropertySource - but found out it doesn't support .yml files
verified to ensure the config server is serving requests to any IP address (there's no IP address filtering)
running curl to ensure the value is brought back
verified to ensure that .jar actually contains bootstrap.yml at jar root
verified to ensure that .jar actually contains Spring Boot classes. FWIW I'm using Maven shade plugin which packages the project into a fat .jar with all dependencies.
Note: AWS Lambda does not support environment variables and therefore I can not set anything like spring.application.name (neither as environment variable nor as -D parameter). Nor I can control the underlying classes which actually launch MyClass - this is completely transparent to the end user. I just package the jar and provide the entry point (class name), rest is taken care of.
Is there anything I could have missed? Any way I could debug this better?
After a bit of debugging I have determined that the issue is with using the Maven Shade plugin. Spring Boot looks in its autoconfigure jar for a META-INF/spring.factories jar see here for some information on this. In order to package a Spring Boot jar correctly you need to use the Spring Boot Maven Plugin and set it up to run during the maven repackage phase. The reason it works in your local IDE is because you are not running the Shade packaged jar. They do some special magic in their plugin to get things in the right spot that the Shade plugin is unaware of.
I was able to create some sample code that initially was not injecting values but works now that I used the correct plugin. See this GitHub repo to check out what I have done.
I did not connect it with Spring Cloud but now that the rest of the Spring Boot injection is working I think it should be straightforward.
As I mentioned in the comments you may want to consider just a simple REST call to get the cloud configuration and inject it yourself to save on the overhead of loading a Spring application with every request.
UPDATE: For Spring Boot 1.4.x you must provide this configuration in the Spring Boot plugin:
<configuration>
<layout>MODULE</layout>
</configuration>
If you do not then by default the new behavior of the plugin is to put all of your jars under BOOT-INF as the intent is for the jar to be executable and have the bootstrap process load it. I found this out while addressing adding a warning for the situation that was encountered here. See https://github.com/spring-projects/spring-boot/issues/5465 for reference.

Categories