Home > Net >  Segregating Springboot app for DEV and PROD Environment for the email app
Segregating Springboot app for DEV and PROD Environment for the email app

Time:01-11

My springboot App is working fine in DEV environment, and now i would like to segregate DEV and PROD environments in order for it to pickup respective code.

I did go through few of the tutorials got some lead to it but was not able to come conclusion on how to separate out PROD section.

This app basically sends an email to gmail on form submission from angular app. This is what i have done till now on the springboot app in order to segregate it.

I have created application-dev.properties and application-prod.properties from the actual application.properties file and added two separate gmail accounts one for DEV and one for PROD. And added the Profiles to POM.xml

Any help on how to create a PROD environment from the existing code will be very helpful. I am quite new to springboot and how to go about doing profiling for different environments.

application.properties file (actual file) is :

server.port=8084

spring.mail.host=smtp.gmail.com
spring.mail.port=587
[email protected]
spring.mail.password=xxxxxxxxxxxxx
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true

New application-dev.properties file

server.port=8084
spring.mail.host=smtp.gmail.com
spring.mail.port=587
[email protected]
spring.mail.password=xxxxxxxxxxxxxxx
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true

spring.profiles.active=@activatedProperties@

New application-prod.properties file

server.port=8085
spring.mail.host=smtp.gmail.com
spring.mail.port=587
[email protected]
spring.mail.password=xxxxxxxxxxxxxxx
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true

POM.xml file

<profile>
  <id>dev</id>
  <properties>
    <activatedProperties>dev</activatedProperties>
  </properties>
  <activation>
    <activeByDefault>true</activeByDefault>
  </activation>
</profile>
<profile>
  <id>prod</id>
  <properties>
    <activatedProperties>prod</activatedProperties>
  </properties>
</profile>

Main EmailClientHmwApplication.java file is as below:

package com.sami.EmailClientHMW;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class EmailClientHmwApplication {

    public static void main(String[] args) {
        SpringApplication.run(EmailClientHmwApplication.class, args);
    }

}

My MailController file which is working with DEV is as :

package com.sami.EmailClientHMW.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.web.bind.annotation.*;


@RestController
public class MailController {

    @Autowired
    private JavaMailSender mailSender;
    @GetMapping("/testsite")
    public String Testing()
    {
        return "Welcome to HMW Email Client Version..New!!";
    }

    @PostMapping("/mail")
    @CrossOrigin
    public String sendmail(@RequestBody MailRequest request) {
        sendSimpleEmail(request.getFrom(), request.getBody(), request.getSubject());
        return "email sent successfully";
    }

    private void sendSimpleEmail(
            String fromEmail,
            String body,
            String subject)
    {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom("[email protected]");
        message.setTo("[email protected]");
        message.setSubject(subject);
        message.setText(body);
            mailSender.send(message);
        System.out.println("From DEV Mail Sent Successfully..hmw!!");
    }
}

MailRequest file:

package com.sami.EmailClientHMW.controller;

public class MailRequest {
    private String from;
    private String to;
    private String subject;
    private String body;

    public String getFrom() {
        return from;
    }

    public void setFrom(String from) {
        this.from = from;
    }

    public String getTo() {
        return to;
    }

    public void setTo(String to) {
        this.to = to;
    }

    public String getSubject() {
        return subject;
    }

    public void setSubject(String subject) {
        this.subject = subject;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }
}

CodePudding user response:

I have created application-dev.properties and application-prod.properties from the actual application.properties

This is already very good (except the exposing secrets in git part...), and you are in fact done!

To activate/override them, you just need to set spring.profiles.active on the according environment.

This can be done trough one of the 14(!) defined property sources in Chapter 2, Externalized Configuration, e.g.:

  • (java.lang.)System property (6.):
    java -jar -Dspring.profiles.active=prod target/myApp.jar 
    
  • also convenient: (5.) Env variables (we have to apply "relaxed rules"..):
    # in windows: SET SPRING_PROFILES_ACTIVE=prod
    export SPRING_PROFILES_ACTIVE=prod
    java -jar target/myApp.jar
    
  • or 11. (different, and more prioritized than 6.):
    java -jar target/myApp.jar --spring.profiles.active=prod
    
  • ... (I recommend something "below 5.", though it is ) also possible in application.properties (3.)

General Tipps:

  • Don't "double maintain" common properties like:
    spring.mail.host=smtp.gmail.com
    spring.mail.port=587
    # ...
    spring.mail.properties.mail.smtp.auth=true
    # ...
    
    for these single location (application.properties) is ok!
  • Use or dev or prod (recommended) properties in application.properties, which adds you "default behavior" (with its benefits (less to care about/maintain) & trade-offs (more to forget/hidden))

How to achieve profile activation on PROD

  • Or use prod properties as application.properties (recommended, "opt-in" DEV other environments)
  • Or activate it in one of the ways proposed above.

How to achieve profile activation on DEV (with IDE)

If we chose DEV as application.properties, then this is also accomplished (and maybe even to prefer for very "dev driven"/prototype environments).

If we chose PROD as application.properties, then we need to do basically the same for DEV - set spring.profiles.active:

  • add spring.profiles.active=dev property to our maven/gradle build (configuration, in IDE)
  • or add --spring.profiles.active=dev parameter on our spring-boot:run (configuration, in IDE)
  • I would not mix maven profiles with spring profiles, if you don't really have good reason for, but if...
  • On the spring-boot-maven(/gradle)-plugin, you can set it like:
    <project>
       <properties>
           <app.profiles>local,dev</app.profiles>
       </properties>
       <build>
           <plugins>
               <plugin>
                   <groupId>org.springframework.boot</groupId>
                   <artifactId>spring-boot-maven-plugin</artifactId>
                   <configuration>
                       <profiles>${app.profiles}</profiles>
                   </configuration>
               </plugin>
           </plugins>
       </build>
    </project>
    
    reference

In Tests

It depends:

  • in which (of all) environment(s) will it run?
  • what profile should it use?

We have the very handy annotation @ActiveProfiles, but its value should be quite "fixed" (for all environments, where tests are run).

When this is not sufficient, consider to introduce an extra profile(group)/setting for tests.

But we can also pass the spring.profiles.active property to (e.g) maven-surefire/failesafe-plugin, like:

<configuration>
  <argLine>-Dspring.profiles.active=${some.maven.property}</argLine>
</configuration>

For Secrets

Spring Boot (admits&) recommends:

Spring Boot does not provide any built in support for encrypting property values, however, it does provide the hook points necessary to modify values contained in the Spring Environment. The EnvironmentPostProcessor interface allows you to manipulate the Environment before the application starts. See howto.html for details.

If you need a secure way to store credentials and passwords, the Spring Cloud Vault project provides support for storing externalized configuration in HashiCorp Vault.

Though container/cloud-driven, spring-boot has no real support for:

Docker Secrets

...but there are several articles/so-questions/github-respositories around, targeting that use case.


More Links:

  •  Tags:  
  • Related