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

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.

Related

REST API returning http status 404 when deployed on EC2 instance on AWS

I have a simple spring boot app which has just 2 rest controllers and I am exporting the war for the same.
I am deploying the same war using the tomcat manager on EC2 instance on AWS, but unfortunately I am getting http status 404 when trying to hit the API.
URL that I am trying to hit is -
[public IP shared by AWS]:[port number on which tomcat is running:8080]/[context route which is the name of my war file]/[my mapped urls]
[publicIP]:8080/aws-0.0.1-SNAPSHOT/login/code
My Controller class
#RestController
#RequestMapping("/login")
public class TestController {
#GetMapping("code")
public String returnCode() {
return "returning code";
}
#GetMapping("received-code")
public String returnReceivedCode(#RequestParam String code) {
return code;
}
}
My pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.test</groupId>
<artifactId>aws</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>aws</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
I tried with java version 8 as well, the tomcat version that I have on my EC2 instance is 9 (apache-tomcat-9.0.70)
I also tried getting one sample war application that tomcat shares for the testing purpose -
https://tomcat.apache.org/tomcat-7.0-doc/appdev/sample/
But surprisingly, this is working fine which tells me that my tomcat and java installations don't have any issues.
Any help would be appreciated.
As highlighted by #khmarbaise above, I was using spring boot 3.0.0 but I had java 8 installed on my EC2 instance and spring boot 3.0.0 requires java version 17+, and that is why I was getting 404 when hitting my APIs.
After downgrading my spring boot version to 2.7.6 I am able to get a corresponding response from the APIs.
Also, as mentioned by other comments regarding the use of "/", omitting the slash was not an issue as the slash is an optional parameter.
Thanks
You have to add a "/" before "code"
#GetMapping("/code")
you forgot to add / for your path in controller methods because of you use path:
/logincode
instead /login/code

Override properties from Azure App Configuration Store

TL;DR
How to have system properties on CLI or environment variables override properties that are provided by an Azure App Configuration Store? Or is this maybe not possible at all?
Longer story
Let us assume a property named app.prop. Let us further assume the following entry in application.yml or in application-<profile>.yml:
app:
prop: Default
Usually, you are able to start the Spring Boot application and provide a system property (e.g. -Dapp.prop=SYS) or an environment variable (e.g. export APP_PROP=ENV) with the effect that the latter overrides the value of the YML config files. If you - for example - provided the environment variable, your application has the value ENV for the property app.prop.
When reading the same property from an Azure App Configuration Store, you can provide a system property or an environment variable as you like. But the value is not overridden anymore; it is the value that is stored in the Azure App Configuration Store.
Some code
I am using Spring Boot version 2.5.7:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.7</version>
</parent>
Further, I am using the following library for accessing the Azure App Configuration Store:
<properties>
<azure-spring-cloud.version>2.7.0</azure-spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>azure-spring-cloud-dependencies</artifactId>
<version>${azure-spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>azure-spring-cloud-appconfiguration-config</artifactId>
</dependency>
</dependencies>
Additionally, for starting the application, I am providing the following property:
spring.cloud.azure.appconfiguration.stores[0].connection-string = ...
This all works very well. In the Azure App Configuration Store, I have the following property:
app.prop = Azure
If now starting the application with the following environment variable APP_PROP = ENV, the value of the property app.prop is still Azure, and not ENV.
Is there any setting missing, so that I can have the same behavior that I had without the above mentioned library?
Actually, I searched a lot, but did not find anything except for some statements regarding overriding values of remote properties in the Spring Cloud documentation, which is not really my case (I am using Azure App Configuration Store).
The whole point of using Azure App Configuration is to store your config in one place and easily manage it without redeploying / restarting the app. Therefore I don't think this is should be even possible.
I would recommend to use labels to load specific version of your prop based on labels data. Few cases:
If you need this property only locally, don't specify it in App Configuration.
If you need multiple versions of it, then just create same property with multiple labels and use your spring.profile (or other conf-property) to distinguish the version.
If you need to load multiple versions of it, load multiple labels:
As described here: https://learn.microsoft.com/en-us/java/api/overview/azure/spring-cloud-starter-appconfiguration-config-readme?view=azure-java-stable#load-from-multiple-labels
You can use this sample to see how it works:
https://github.com/Azure/azure-sdk-for-java/tree/azure-spring-boot_3.6.0/sdk/appconfiguration/spring-cloud-starter-azure-appconfiguration-config

Inject property value from settings.xml during test profile run

I added a new functionality to my service where I now consume messages from rabbitMq. This works great and pretty much right out of the box with Spring Boot.
However, in order to not add the credentials to source control, I have been trying to inject the password from my user's settings.xml. This works as intended when I stand up the service locally with its default/production profile, but it does not when I run the test suite (test profile).
Below is an example of my settings.xml:
<settings
...
<profiles>
<profile>
<id>inject-properties</id>
<properties>
<prod.rabbit.pwd>someProdPwd</prod.rabbit.pwd>
<test.rabbit.pwd>someTestPwd</test.rabbit.pwd>
</properties>
</profile>
</profiles>
<activeProfiles>
<activeProfile>inject-properties</activeProfile>
</activeProfiles>
</settings>
I run mvn help:active-profiles to validate it activates:
The following profiles are active:
- inject-properties (source: external)
- package (source: com.myservice:myservice:1.16.0-SNAPSHOT)
Then, in my application.properties I define the property as follows:
spring.rabbitmq.password=#prod.rabbit.pwd#
I stand up the service, and I can see the property being replaced by the value in settings.xml, so that part looks good.
Then, in my application-test.properties, I have:
spring.rabbitmq.password=#test.rabbit.pwd#
But when I proceed to run my tests, that does not work as it did before. When the rabbit bean is instantiated by the spring boot context builder, it passes the literal value #test.rabbit.pwd#, which fails authentication and causes the service not to stand up/test not to run.
Anyone ever run into this weird behavior? I found this question, which is pretty much the same issue I am having from a while back, but it did not really have a solution. Replace property placeholders in spring profile-specific properties file

Change CodeStar Spring MVC project to Spring Boot

I have a Spring Boot project that works perfectly when run in IDE. I would like to run this via AWS CodeStar. Unfortunately, the default Spring template created by CodeStar uses Spring MVC.
I cannot just overwrite the default Spring MVC project with my Spring Boot project (it doesn't work). I can copy some of my resources to the MVC project, for example index.html and that works. But then features like Thymeleaf don't work. For this and other reasons, I would like to change the provided Spring MVC into the Spring Boot structure I already have.
I followed the instructions here: https://www.baeldung.com/spring-boot-migration
Unfortunately, this doesn't help. I can create Application Entry Point and add Spring Boot dependencies without the app breaking. But when I remove the default dependencies or the configuration associated with the MVC, the app breaks. When trying to reach the URL, I get a 404 error with description:
The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.
Debugging this error message (e.g. https://www.codejava.net/java-ee/servlet/solved-tomcat-error-http-status-404-not-found) didn't help.
The message seems like it's connected to the web resource. I have my web resources in folder resources as well as webapp/resources. And Spring Boot doesn't need any location configuration, right? It uses this location by default.
Can somebody tell me what things to remove and what to add to be able to use my existing Spring Boot project?
EDIT:
This is a link to a default template for AWS CodeStar Spring web application: https://github.com/JanHorcicka/AWS-codestar-template
And this is my Spring Boot project structure:
I realize that you indicated that previously you tried to use your Spring Boot project with some modifications without success, but I think it could be actually a possibility to successfully deploy your application on AWS CodeStar, and it will be my advice.
I also realized that in your screenshot you included several of the required artifacts and classes, but please, double check that you followed these steps when you deployed your application to AWS CodeStar.
Let's start with a pristine version of your Spring Boot project running locally, without any modification, and then, perform the following changes.
First, as indicated in the GitHub link you shared, be sure that you include the following files in your project. They are required for the deployment infrastructure of AWS:
appspec.yml
buildspec.yml
template.yml
template-configuration.json
The whole scripts directory
Please, adapt any necessary configuration to your specific needs, especially, template-configuration.json.
Then, perform the following modifications in your pom.xml. Some of them are required for Spring Boot to work as a traditional deployment and others are required by the deployment in AWS CodeStar.
Be sure that you indicate packaging as war:
<packaging>war</packaging>
To ensure that the embedded servlet container does not interfere with the Tomcat to which the war file is deployed, either mark the Tomcat dependency as being provided as suggested in the above-mentioned documentation:
<dependencies>
<!-- … -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- … -->
</dependencies>
Or exclude the Tomcat dependency in your pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
If necessary, apply this exclusion using some kind of profile that allows you to boot Spring Boot locally and in an external servlet container at the same time.
Next, parameterize the maven war plugin to conform to the AWS CodeStar deployment needs:
<build>
<pluginManagement>
<plugins>
<!-- ... -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<warSourceDirectory>src/main/webapp</warSourceDirectory>
<warName>ROOT</warName>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<!-- ... -->
<plugins>
</pluginManagement>
</build>
I do not consider it necessary, but just to avoid any kind of problem, adjust the name of your final build:
<finalName>ROOT</finalName>
Lastly, as also indicated in the Spring documentation, be sure that your MyProjectApplication - I assume this class is your main entry point subclass SpringBootServletInitializer and override the configure accordingly, something like:
#SpringBootApplication
public class MyProjectApplication extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(MyProjectApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(MyProjectApplication.class, args);
}
}
Please, feel free to adapt the class to your specific use case.
With this setup, try to deploy your application and see if it works: perhaps you can find some kind of library dependencies problem, but I think for the most part it should work fine.
At a first step, you can try to deploy locally the version of the application you will later deploy to AWS CodeStar following the instructions you provided in your project template, basically, once configured with the necessary changes described in the answer, by running:
mvn clean package
And deploying the generated war on your local tomcat environment. Please, be aware that probably the ROOT application already exists in a standard tomcat installation (you can verify it by inspecting the webapps folder): you can override that war file.
For local testing you can even choose a different application name (configuring build.finalName and the warName in your pom.xml file): the important thing is verify if locally the application runs successfully.
If you prefer to, you can choose to deploy the app directly to AWS CodeStar and inspect the logs later it necessary.
In any case, please, pay attention on two things: on one hand, if you have any absolute path configured in your application, it can be the cause of the 404 issue you mention in the comments. Be aware that your application will be deployed in Tomcat with context root '/'.
On the other hand, review how you configured your database access.
Probably you used application.properties and it is fine, but please, be aware that when employing the application the database must be reachable: perhaps Spring is unable to create the necessary datasources, and the persistence manager or related stuff associated with and, as a consequence, the application is not starting. Again, it may be the reason of the 404 error code.
To simplify database connectivity, for testing, at first glance, I recommend you to use simple properties for configuring your datasource, namely the driver class, connection string, username and password. If that setup works properly, you can later enable JNDI or what deemed necessary.
Remember that if you need to change your context name and/or define a datasource pool in Tomcat you can place a context.xml file under a META-INF directory in your web app root path.
This context.xml should look like something similar to:
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/">
<Resource name="jdbc/myDS"
type="javax.sql.DataSource"
maxActive="100"
maxIdle="30"
maxWait="10000"
url="jdbc:mysql://localhost:3306/myds"
driverClassName="com.mysql.jdbc.Driver"
username="root"
password="secret"
/>
</Context>

Display build timestamp in Spring Boot actuator info endpoint

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.

Categories