Spring Boot + Gradle - where to put environment configuration? - java

I was working on a simple application in Spring Boot. It was developed locally (and it works) with:
Gradle,
H2 database with connection properties set in application.properties placed on project's root
Maven folders structure (src/main/groovy, src/main/resources, etc.)
Now it's the time when I'd like to deploy it to the Openshift, so I need to create an additional, production configuration with a MySQL settings, but I don't know where to put it and how to use it.
So my questions are:
What should I do to have two different configurations (development and production)?
Where to put the configuration files?
Do I have to change something in the build.gradle?
How to build the app with a development or production config?
How to run the app with a development or production config?
What are the best practices for creating multiple environment configurations?
I'm rather a frontend dev and all these backend stuff are not obvious for me, so please consider it in your answers.
This is the content of my current build.gradle
plugins {
id 'org.springframework.boot' version '1.5.3.RELEASE'
id 'java'
id 'groovy'
}
jar {
baseName = 'myproject'
version = '0.0.1-SNAPSHOT'
}
repositories {
jcenter()
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
testCompile("org.springframework.boot:spring-boot-starter-test")
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile 'mysql:mysql-connector-java'
compile("com.h2database:h2")
compile("org.springframework.boot:spring-boot-starter-security")
compile('io.jsonwebtoken:jjwt:0.7.0')
compile localGroovy()
}

What should I do to have two different configurations (development and production)?
In your case, you can use a profiles to achieve it. You can read about it here. For each profile you can have specific application properties file (named application-%PROFILE_NAME%.properties, like application-prod.properties, the same is true for .yml configuration files) And you have to specify what profile yo use then you are starting your app via command line switch for example like so:
--spring.profiles.active=prod
Where to put the configuration files?
Just in the same place as your application.properties file.
Do I have to change something in the build.gradle?
No, you don't need to modify your build script. Since all specific configurations are needed for running your application, not for building.
How to build the app with a development or production config?
You don't need to build it with some specific configuration, just run it with it.
How to run the app with a development or production config?
As it was said earlier - just specify what profile to use when starting the application.
What are the best practices for creating multiple environment configurations?
As for me, if you use a spring - to use profiles and profile specific configuration and bean-definitions.

Create a separate application-dev.properties along side your existing application.properties files as outlined here to contain your h2 config https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-profile-specific-properties and then activate this when running in dev by passing in the following argument when starting the app --spring.profiles.active=dev you could do the same for production i.e. application-prod.properties and keep the common configuration in application.properties.

Related

How to manage Environment and Region/location Specific Configuration using Maven

We have following 3 [DEV,STAGING,PROD] environment. And multiple regions/location under each environment example [ ASIA,EUROPE,US ]. What is best way we can configure the project using maven so that it can pick correct configuration xml and properties based on the environment and region.
For example: if we want to test/build our application in STAGING on US region, STAGING-US.xml , STAGING-US.properties should be taken during the build.
Our application is Maven based .
It would be great help if you could suggest any other better alternative also, we are trying to use maven profile. But it seems we have to create multiple profiles.

Gradle multi-project build order using Kotlin script

I use Kotlin DSL script (.kts) for building. There the structure of my project is:
Root project 'demo'
+--- Project ':backend'
\--- Project ':frontend'
I need to build project frontend first, than backend. I tried
include(":frontend")
include(":backend)
and
include(":frontend", ":backend")
with and without : in settings.gradle.kts of root project, but still the order of build is alphabetical - backend, than frontend.
View source code on GitHub
Do you have any ideas what is wrong?
There is nothing wrong. If you don't specify any inter-project dependencies, Gradle will execute them in alphabetical order. This should be fine if the two projects are unrelated, as they are now.
But let's say you like to build the frontend (using node) and then include those resources in the backend (using Spring Boot). Then you will need to make the backend depend on frontend project. Then Gradle will honor the dependency graph and build the frontend first.
There are many ways to do that. One is to use the java plugin in the frontend to build a jar file of your frontend resources. You can then make a normal project dependency to it. You could also make a dependency directly into the frontend project's "internal" build tasks, but that is a bit frowned upon. Or you could declare your own artifact, or do a it in a bunch of other different ways.
For the first approach, you can build a jar file of your frontend resources like this:
plugins {
// ...
id("java")
}
java {
// Required to make the jar artifact compatible with your backend, which is configured for Java 1.8
targetCompatibility = JavaVersion.VERSION_1_8
}
tasks.named("jar", Jar::class) {
dependsOn("assembleFrontend")
from("$buildDir/dist")
into("static")
}
Then in the backend, depend on it like this:
dependencies {
// ...
runtimeOnly(project(":frontend"))
}
There are a few other things wrong with your build script as well.
The runtime configuration is deprecated; use runtimeOnly instead (for your spring-boot-devtools dependency).
A multi-project should only have a single settings.gradle file, but you have one in each project. Delete them except for the one in the root folder.
You have declared the org.siouan.frontend plugin twice: once using the recommended way and once using the "old" way. Remove the latter (everything in the buildscript block and the apply statement.
Also, while I am not familiar with the org.siouan.frontend plugin, it appears it does not declare inputs and outputs for you - probably because it is very generic. So to avoid running npm each time you build your backend (as you now have a dependency to the frontend), you should declare proper inputs and outputs for the frontend tasks like installFrontend and assembleFrontend.

Grails project with no Build.Groovy file. How to add plugins

I am currently trying to add Redis Hibernate cache plugin to my Grails/Gradle project. However, in the configuration folder, there exists no BuildConfig.Groovy file, and the instructions instruct to add the dependency and other configs to this file.
This project was not created by me, however I am working on it as a collaborator.
There exists a Build.Gradle file, but there are no instructions on how to configure/add this dependency here.
Below is a screenshot of the instructions on the Grails Plugins page.
If you have a build.gradle file then you're in grails 3 as far as I know. You may want to view documentation here: http://plugins.grails.org/plugin/ctoestreich/redis but in short, you will need to add a compile-time dependency there rather than BuildConfig.groovy.
Add or modify your dependencies block to contain:
dependencies {
compile 'org.grails.plugins:redis:2.0.5'
}
Or any other plugins as needed.

Eclipse does not pass mail properties to Spring Boot after migration

I am migrating my Spring Boot application from version 1.5.7 to 2.0.0 and I noticed that it no longer takes mail properties from ENV variables for some reason.
I am using java.mail.Sender and have the following propeties in my application.properties file:
spring.mail.host=smtp.example.com
spring.mail.username=username
spring.mail.password=password
spring.mail.port=587
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.defaultEncoding=UTF-8
This is there just to mock the mail properties in tests. I am injecting the real ones using the same keys as ENV variables: spring.mail.host=smtp.google.com, etc.
But when I try to send the email, I see that it is still using smtp.example.com. I thought that ENV variables had higher priority than values from application.properties. Did something change? Everything worked fine in Spring Boot 1.5.7.
EDIT:
The following command works so it is definitely some problem with Eclipse:
SPRING_PROFILES_ACTIVE=development SPRING_MAIL_HOST=smtp.gmail.com SPRING_MAIL_USERNAME=xxx SPRING_MAIL_PASSWORD=xxx ./gradlew clean bootRun
What I don't understand is why the exact same configuration works, when I switch back to 1.5.7. It is also strange that when passign env variables via Eclipse run configuration, it works for profile. So some env variables are applied and some not...
I was able to recreate this issue. Created a Spring boot App with 1.5.X and injected Environment variables from Eclipse. Now, when I migrate to 2.X release, the environment variables are not getting injected.
On further analysis, found out this interesting thread
One of the Spring-boot developers made this comment
Hence my conclusion is when we are using 2.X release, there is one of the component within Spring-boot-parent which is making the spring boot maven plugin to fork it and run in a separate JVM. Thus, the environment variable is not getting passed.
That answers the question why profile value is picked-up from the environment section. Profile flag is always passed as an argument irrespective of whether the app runs in the maven JVM or a new one
To confirm this, you can add the config entries to the JVM argument tab like the one below
You will now be able to see the new values passed to spring boot
I don't know much about your configurations, but if the project structure is okay with correct dependencies and the application.properties exit under src/main/resources and your startup class annotated with #SpringBootApplication, it should work fine.
you can test if the application reads your properties file by injecting a variable String with annotation #Value inside any class and log or print it.
#Value("${spring.mail.host}")
private String host;
first Make sure your IDE is running on Java 8 or later version .
With Spring Boot 2.0, many configuration properties were renamed/removed and developers need to update their application.properties/application.yml accordingly. To help you with that, Spring Boot ships a new spring-boot-properties-migrator module. Once added as a dependency to your project, this will not only analyze your application’s environment and print diagnostics at startup, but also temporarily migrate properties at runtime for you. This is a must have during your application migration:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-properties-migrator</artifactId>
<scope>runtime</scope>
</dependency>
runtime("org.springframework.boot:spring-boot-properties-migrator")
Note Once you’re done with the migration, please make sure to remove this module from your project’s dependencies.
For more information follow this link
Spring Boot 2.X migration guide

Does anyone know how to build a gradle parent project with subprojects that uses the tomcat plugin

I am devolping a parent java project with 3 subprojects. I am using gradle as its build tool. I am new to using gradle for my build tool.
I am trying to get it to when I run the parent project, the parent project and possibly two of the subprojects automatically run on a web application (Tomcat web container).
I found a helpful website https://github.com/bmuschko/gradle-tomcat-plugin/blob/master/README.md
I see that I have to add a few things to the parent projects build.gradle. For instance:
apply plugin: 'tomcat'
which defines the following tasks:
tomcatRun: Starts a Tomcat instance and deploys the exploded web application to it.
tomcatRunWar: Starts a Tomcat instance and deploys the WAR to it.
tomcatStop: Stops the Tomcat instance.
tomcatJasper: Runs the JSP compiler (Jasper) and turns JSP pages into Java source using.
I would need to run the "tomcatRun" and the "tomcatStop" task. Where should I declare each task? I think I should declare it under repositories { } tomcatRun { ...., but I am not sure. Is that where I would declare it? Do I have to declare the httpPort if my port is 8080? I ask, because 8080 is the default value and I am using the default value?
I have to declare the classpath for tomcat (classpath 'org.gradle.api.plugins:gradle-tomcat-plugin:0.9.7') inside the dependencies. Right?
For each of the subprojects that I want to add to tomcat, do I have to delare the classpath in their dependencies in their 'project' section (project (':subproject-a') { dependences { classpath ... ?
I added aplly plugin:'tomcat', but when I run it I get "Plugin with id 'tomcat' not found. What am I missing?
Where do I define the tomcat options?
[tomcatRun, tomcatRunWar]*.contextPath = 'stock-webservice'
[tomcatRun, tomcatRunWar, tomcatStop]*.stopPort = 8081
[tomcatRun, tomcatRunWar, tomcatStop]*.stopKey = 'stopKey'
Many of your questions should have been answered by the plugin's documentation. First of all, the tasks you mention are provided by the plugin. You do not need to declare them yourself. Run gradle tasks for a list of task available to your project. If a default is given for a property, then you don't need to provide it. Tomcat dependencies are assigned to the tomcat configuration. You can just copy/paste the relevant code from the README file. If the plugin cannot be found, that means you didn't declare the plugin dependency for your buildscript's classpath. Again you can copy/paste the relevant code from the documentation.
In general I'd recommend reading up on the Gradle online documentation first to get a better understanding of the tool.

Categories