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
Related
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.
I've got a project with Serenity properties file configuration and I want to put a security code before to start the test, so at the beginning when I prepare the test, I clean the value like this:
...
serenity.timeout=1000
secretVariable=
serenity.verbose.steps=FALSE
...
but when I run the test, I want to change the serenity.properties like this:
...
serenity.timeout=1000
secretVariable=24C20-00034D2
serenity.verbose.steps=FALSE
...
So , my question is, is this possible using a java code and/or maven configuration?
If you want to change some non-configuration file settings, I may only provide configuration related to the springboot project, you can set your vm option:
--serenity.timeout=1000
--secretVariable=24C20-00034D2
--serenity.verbose.steps=FALSE
Or you can modify the args parameter of your launch:
String[] arg=new String[3];
arg[0]="--serenity.timeout=1000";
arg[1]="--secretVariable=24C20-00034D2";
arg[2]="--serenity.verbose.steps=FALSE";
This is the method I can think of. I have not tried to use maven to manage these parameter configurations, but I have used maven to manage parameter modules. You can use this method to manage, and it supports .yml and .proerties, I will give you an example, but for the specific usage method, you need to go to the official springboot documentation to find the detailed usage method:
maven:
<!--Configure maven multi-environment development-->
<profiles>
<profile>
<id>enc_dev</id>
<properties>
<profile.active>dev</profile.active>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>enc_dev</id>
<properties>
<profile.active>dev</profile.active>
</properties>
</profile>
</profiles>
application.proerties:
spring.profiles.active=#profile.active#
spring.profiles.group.dev=devMVC,devDB
spring.profiles.group.pro=proMVC
This way you can easily manage the modules you want and do targeted configuration, hope this helps you.
I am trying to run a Spring boot application on my local machine. When I use the following syntax for a property it resolves well:
username: ${project.db.user}
However the following raises an exception:
username: ${PROJECT_DB_USER}
Is there any way to use uppercase here? My CI/CD pipelines defines all its variables with uppercase
I've had similar problems, and from what I've understood, since springBoot v2.1, the application.properties files don't handle environement variables well. The solution is to use Spring Profiles.
You need to add as many .properties files as you have environments, like so :
application.properties
application-staging.properties
application-prod.properties
If you have a staging and prod profiles. The .properties of the profile overrides the basic application.properties, so be sure not to forget anything in each file !
There may be other solutions as well.
You can set the profiles using various methods, in Spring boot, with Maven (sorry, the only one I'm familiar with) you can simply add it to the pom.xml like this :
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<profiles>
<profile>staging</profile>
</profiles>
</configuration>
</plugin>
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>
In my Maven build I would like to be able to define default values (e.g. for database connection) in pom.xml, but I would like the user to be able to override these without having to modify pom.xml directly.
By way of example, in an Ant build you can define default properties in foo.properties, but Ant will look for overrides for each of these in a foo.$USERNAME.properties. The latter is generally not checked into source control, which eliminates the problem of developers accidentally committing their overrides of the default properties. Does Maven offer a similar facility?
To make the problem a bit more concrete, assume I have the following defined in pom.xml
<properties>
<db.url>jdbc:jtds:sqlserver://10.10.10.10:1433/somedb</db.url>
<db.driver>net.sourceforge.jtds.jdbc.Driver</db.driver>
<db.username>default_user</db.username>
<db.password>secret</db.password>
</properties>
Can a user override these properties without editing the pom.xml directly?
You can specify properties on the command line using -Dpropertyname=value, or the user can specify properties in their .m2/settings.xml.
You can achieve this with build profiles. See Introduction to build profiles for more information.
I used settings.xml to override these properties by adding the following to the <profiles> section
<profile>
<id>override-database-properties</id>
<activation>
<property>
<name>refreshDB</name>
</property>
</activation>
<properties>
<db.schema_name>store_don</db.schema_name>
</properties>
</profile>
In this case the overrides will only take effect if a -DrefreshDB is passed to the mvn command. To activate these overrides every time Maven is invoked also add the following to settings.xml
<activeProfiles>
<activeProfile>alwaysActiveProfile</activeProfile>
</activeProfiles>
If the profile is added to <activeProfiles> then the <activation> element should be removed.
If you don't want to add properties on the command line, but set some settings once (and if you can accept the default being empty strings); you could use environment variables like this:
<something>${env.ENVNAME}</something>
<!-- something will be blank "" unless ENVNAME is set -->
Edit: I've been trying to find a way of defining a default values for ${variable} if the variable is empty/undefined, but I've not found anything, this seems to be missing (the frequent suggestion is to use profiles but it's not quite the same).
I'd prefer if you could just set some environment variables and have sensible defaults so that you could just run mvn clean install (and not the 20-40 character strings I normally use to build our project). If default values is possible I'd love hear how...
BTW, if you're already used to Ant, I've heard that you can call Ant tasks from maven somehow (don't know how, though), maybe you could use that somehow?