Setting and Reading Active Profiles

This article shows different ways to set the active profile that requires java code change. We can then activate different profiles in different environments based on some application logics. Also, we can list the list of active profiles as shown in the below examples. The article is divided into two sections, one for setting the active profile and the other one is listing the active profiles.

Setting though setAdditionalProfiles.

RestApplication
The following example shows how to set the active profile "prod" by calling setAdditionalProfiles from the Spring Application Class. We need to set the profiles before the run method.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@ComponentScan({"com.bootng", "com.bootng.service"})
@SpringBootApplication
public class RestApplication {

  private static final Logger log = LoggerFactory.getLogger(RestApplication.class);

  public static void main(String args[]) {
    log.info("about to call RestApplication.run()");

    // set extra profile
    SpringApplication application = new SpringApplication(RestApplication.class);
    application.setAdditionalProfiles("prod");
    application.run(args);
    log.info("completed executing RestApplication.run()");
  }
}

Listing Active Spring Boot Profiles by @Value

@Value
the property spring.profiles.active contains the list of active profiles. We can read this value by @Value annotations
@Value("${spring.profiles.active:}")

Listing Active Spring Boot Profiles by Environment

Through org.springframework.core.env.Environment
The following code shows how to read the list of active profiles by using org.springframework.core.env.Environment object.
@Autowired
private Environment environment;

//read the active profiles from environment object.
String result = "Currently active profile - ";
for (String profileName : environment.getActiveProfiles()) {
    result+=" " + profileName;
}  

References


How to set active profiles

Spring Boot applications can have more than one Profiles. Sometimes we need to set the active profile so that the application reads the appropriate properties or Beans. This article demonstrates some of the different ways to set the Spring Active Profile though properties file and environment variables setting which does not need code chage.

By application.properties

Set Active Spring Profiles In the application.properties file
We can set active profiles for Spring Boot applications in the application.properties file, as shown in the bellow. Here we are setting prod profile as active profile.
spring.profiles.active=prod

Environment variable

Set Active Spring Profiles by setting an Environment variable
Following example, we are setting the Environment variable, which would be read by the Spring Boot Application.
export spring_profiles_active=dev

JVM System Properties

Set Active Spring Profiles by using JVM System Properties
Following the example, we are setting the active profile by setting JVM system property Dspring.profiles.active.
java -jar -Dspring.profiles.active=prod bootng-springboot-profiles-1.0.0-SNAPSHOT.jar


With Maven plugin

When using Maven plugin use the following command to pass the active profiles.
mvn spring-boot:run -Dspring-boot.run.profiles=prod,dev

References




Spring Boot Logging with Logback

In this article we will cover some important concepts about logging with Spring Boot and Logback. Spring Boot uses Commons Logging for all internal logging but leaves the underlying log implementation open. Spring Boot supports logging using Java Util Logging, Log4J2, and Logback. By default, if we use the “Starters”, Logback is used for logging. In this article we will work with Logback for logging with a Spring Boot Application. Logback Loggers may be assigned levels. The set of possible levels are (TRACE, DEBUG, INFO, WARN and ERROR) We will go through the details of turning on Logging at different levels also different levels under different environments (different Profiles)

Purpose

In this article we will walk through a simple Spring Boot application configured with logback for logging. In this application, we will enable different logging under different profiles though logback_profile.xml file.
Application Details
ProfileController controller contains log messages for each log level (TRACE, DEBUG, INFO, WARN, and ERROR). This controller can be accessed at localhost:8080/profiles. The controller will return the name of the active profile to the browser. This controller will write log messages to the console with different available levels as per the active profile. We configure the different log level for different profiles using logback-profile.xml

Project Structure


Technology used
Spring Boot 2.2.6.RELEASE Logback 1.2.3 Maven 3 Java 11

Code reference

applications.properties
# if no active profile, default is 'default'
# spring.profiles.active=dev
mail.smtp.host=localhost.mail.com
mail.smtp.port=0000  
mail.smtp.user=rootadmin
appserver.version=1

# logging level
logging.level.org.springframework=ERROR
#logging.level.com.bootng=DEBUG
# root level
#logging.level.=INFO
# output to a file
logging.file=springboot-profile-app.log
logging.pattern.file=%d %p %c{1.} [%t] %m%n
logging.pattern.console=%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
 <springProfile name="default">
  <appender name="stdout"
   class="ch.qos.logback.core.ConsoleAppender">
   <encoder>
    <pattern>%d{yy-MMMM-dd HH:mm:ss:SSS} %5p %t %c{2}:%L - %m%n
    </pattern>
   </encoder>
  </appender>
  <root level="DEBUG">
   <appender-ref ref="stdout" />
  </root>
  <logger name="com.bootng" level="DEBUG" />
 </springProfile>

 <springProfile name="dev">
  <logger name="com.bootng" level="DEBUG" />
 </springProfile>

 <springProfile name="prod">
  <logger name="com.bootng" level="ERROR" />
 </springProfile>
</configuration>
ProfileController
@Controller
public class ProfileController {
 private static final Logger logger = LoggerFactory.getLogger(ProfileController.class);
 @Autowired
  private Environment environment;
  @RequestMapping(value = {"/profile"}, method = RequestMethod.GET,
      produces = MediaType.APPLICATION_JSON_VALUE)
  public @ResponseBody ResponseEntity <String> paymentInfo() {
    logger.trace("Inside GET profile");
    logger.debug("Inside GET profile");
    logger.info("Inside GET profile");
    logger.warn("Inside GET profile");
    logger.error("Inside GET profile");
    
    String result = "Currently active profile - ";
    for (String profileName : environment.getActiveProfiles()) {
       result+=" " + profileName;
    }  
    return new ResponseEntity<String>(result, HttpStatus.OK);
  }
 }

Run Application

With dev profile
Run the application in with active profile=dev and go to localhost:8080/profile. You can see the following logs.
mvn spring-boot:run -Dspring-boot.run.profiles=dev
Console
01:39:43.304 [http-nio-8080-exec-1] TRACE com.bootng.ProfileController - Inside GET profile
01:39:43.305 [http-nio-8080-exec-1] DEBUG com.bootng.ProfileController - Inside GET profile
01:39:43.305 [http-nio-8080-exec-1] INFO com.bootng.ProfileController - Inside GET profile
01:39:43.305 [http-nio-8080-exec-1] WARN com.bootng.ProfileController - Inside GET profile
01:39:43.305 [http-nio-8080-exec-1] ERROR com.bootng.ProfileController - Inside GET profile
With prod profile
Run the application in with active profile=prod and go to localhost:8080/profile. You can see the following logs.
mvn spring-boot:run -Dspring-boot.run.profiles=prod
Console
1:40:27.179 [http-nio-8080-exec-1] ERROR com.bootng.ProfileController - Inside GET profile
You can see the difference in the logs from the same controller under different profiles.

Summary and Git Project

Download Source Code
git clone git@github.com:bootng/spring-boot-references.git cd spring-boot-profiles #Build the project mnv install # Run the application with dev set as the active profile mvn spring-boot:run -Dspring-boot.run.profiles=dev # Run the application with prod set as the active profile mvn spring-boot:run -Dspring-boot.run.profiles=prod
Summary
We can configure log levels differently for different packages. We can configure a log for different profiles using the springProfile tag. Logback recommends using logback-spring.xml for configuring logs. logback-spring.xml is optional and used to control the logs though different appenders or levels. we can also turn on logs for different packages or root using application.properties

References


Example with Spring Profiles

In continuation of the Spring Boot profiles, in this article we will walk through different use cases. We will see how to read property files and display them through a controller. We have following use cases 1)Defining and reading profile-specific beans 2) populating beans from a properties file.

Purpose

In this article, we will build a Spring Boot Application with a two-controller and 2 profile-specific configuration files.

Code structure


Spring Boot Application Structure


Technology Used
Java 11
Spring Boot 2.2.6.RELEASE
Maven 3.5.0
Eclipse IDE

Application details

This application we have one controller EmailController which shows some data to the response. These data are collected from different Java classes. Each java class is populated by Spring in a different way. PaymentProperties: This defines a bean-based on profile. When we read the bean PaymentProp from EmailController it shows the data based on the active profile. MailSenderProperties: It is populated by the active profile property file. ContactProperties and AddressProperties: These objects are populated from the respective properties file and have nothing to do with an active profile.

Code details

pom.file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <artifactId>bootng-springboot-profiles</artifactId>
 <version>1.0.0-SNAPSHOT</version>
 <packaging>war</packaging>
 <name>com.bootng Springboot Profile</name>
 <description>com.bootng Springboot Profile</description>
 <parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.2.6.RELEASE</version>
  <relativePath />
 </parent>
 <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  <java.version>1.8</java.version>
 </properties>
 <dependencies>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
   <groupId>org.junit.jupiter</groupId>
   <artifactId>junit-jupiter-api</artifactId>

  </dependency>
 </dependencies>
 <build>
  <plugins>
   <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
     <addResources>true</addResources>
    </configuration>
    <executions>
     <execution>
      <goals>
       <goal>repackage</goal>
      </goals>
     </execution>
    </executions>
   </plugin>
  </plugins>
 </build>
</project>
Application Class
@ComponentScan({"com.bootng", "com.bootng.service"})
@SpringBootApplication
public class RestApplication {
  private static final Logger log = LoggerFactory.getLogger(RestApplication.class);
  public static void main(String args[]) {
    log.info("about to call RestApplication.run()");
    application.run(args);
    log.info("completed executing RestApplication.run()");
  }
}
EmailController
package com.bootng;

@Controller
public class EmailController {
  @Autowired
  public MailSenderProperties mailSender;
  @Autowired
  private ContactProperties contact;
  @Autowired
  private AddressProperties address;
  @Autowired
  private ApplicationContext applicationContext;
  @Value("${appserver.version}")
  private String paymentServerVer;
  @RequestMapping(value = {"/details"}, method = RequestMethod.GET,
      produces = MediaType.APPLICATION_JSON_VALUE)
  public @ResponseBody ResponseEntity <String> paymentInfo() {
    
    //Get the Bean with name PaymentProp
    HashMap<String, String> paymentProp = (HashMap<String, String>) applicationContext.getBean("PaymentProp");
    
    //Get the payment Server version from application.properties file
    String paymentInfo ="\nPayment Server Version:= " +  paymentProp.toString();
    
    String smtpInfo = "\n Mail Server SMTP Host: " + mailSender.getSmtpHost() + " SMTP Port:"
        + mailSender.getSmtpPort();
    
    String info = "\nContactInfo From=" + contact.getFrom() + " Email=" + contact.getFromEmail();
    String addressInfo = "\n AddressInfo Street=" + address.getStreet() + 
                         " City=" + address.getCity() +
                         " State=" + address.getState() +
                         " Zip=" + address.getZip();
    String result = paymentInfo + smtpInfo + info + addressInfo;
    return new ResponseEntity<String>(result, HttpStatus.OK);
  }
  
  @RequestMapping(value = {"/smtp"}, method = RequestMethod.GET,
      produces = MediaType.APPLICATION_JSON_VALUE)
  public @ResponseBody ResponseEntity<String> sendEmail() {

    String result = "<br>Mail Server SMTP Host: " + mailSender.getSmtpHost() + " SMTP Port:"
        + mailSender.getSmtpPort();

    return new ResponseEntity<String>("email sent" + result, HttpStatus.OK);
  }
  
  @RequestMapping(value = {"/address"}, method = RequestMethod.GET,
      produces = MediaType.APPLICATION_JSON_VALUE)
  public @ResponseBody ResponseEntity <String> getAddress() {
  
    String info = "From=" + contact.getFrom() + " Email=" + contact.getFromEmail();
    String addressInfo = " Street=" + address.getStreet() + 
                         " City=" + address.getCity() +
                         " State=" + address.getState() +
                         " Zip=" + address.getZip();
   
    return new ResponseEntity<String>(info + addressInfo, HttpStatus.OK);
  }
}
PaymentProperties
@Configuration
public class PaymentProperties {
  @Profile("dev")
  @Bean(name="PaymentProp")
  public HashMap<String, String> getPaymentServerDev() {
      HashMap<String, String> paymentMethod = new HashMap<>();
      paymentMethod.put("Currency", "USD");
      paymentMethod.put("ChargePercentage", "1");
      paymentMethod.put("Gateway", "BOA");
      return paymentMethod;
    }
  @Profile("prod")
  @Bean(name="PaymentProp")
  public HashMap<String, String> getPaymentServerProd() {
      HashMap<String, String> paymentMethod = new HashMap<>();
      paymentMethod.put("Currency", "Pound");
      paymentMethod.put("ChargePercentage", "4");
      paymentMethod.put("Gateway", "BankOfEngland");
      return paymentMethod;
    }
}
MailSenderProperties
@Component
@PropertySource("classpath:application-${spring.profiles.active}.properties")
public class MailSenderProperties {
  @Value("${mail.smtp.host}")
  private String smtpHost;

  @Value("${mail.smtp.port}")
  private Integer smtpPort;
  public String getSmtpHost() {
    return smtpHost;
  }
  public void setSmtpHost(String smtpHost) {
    this.smtpHost = smtpHost;
  }
  public Integer getSmtpPort() {
    return smtpPort;
  }
  public void setSmtpPort(Integer smtpPort) {
    this.smtpPort = smtpPort;
  }
}
ContactProperties
@Component
@ConfigurationProperties(prefix = "contact")
@PropertySource("classpath:office-address.properties")
@Validated
public class ContactProperties {
  @NotNull
  private String from;
  @Email
  private String fromEmail;
  @Value("${contact.fromTwitter}")
  private String twitterHandle;

  public String getFrom() {
    return from;
  }
  public void setFrom(String from) {
    this.from = from;
  }
  public String getFromEmail() {
    return fromEmail;
  }
  public void setFromEmail(String fromEmail) {
    this.fromEmail = fromEmail;
  }
  public String getTwitterHandle() {
    return twitterHandle;
  }
  public void setTwitterHandle(String twitterHandle) {
    this.twitterHandle = twitterHandle;
  }
}
AddressProperties
@Component
@PropertySource("classpath:office-address.properties")
@Validated
public class AddressProperties {
  @Value("${address.street}")
  private String street;
  @Value("${address.city}")
  private String city;
  @Value("${address.state}")
  private String state;
  @NotNull
  @Value("${address.zip}")
  private String zip;
  public String getStreet() {
    return street;
  }
  public void setStreet(String street) {
    this.street = street;
  }
  public String getCity() {
    return city;
  }
  public void setCity(String city) {
    this.city = city;
  }
  public String getState() {
    return state;
  }
  public void setState(String state) {
    this.state = state;
  }
  public String getZip() {
    return zip;
  }
  public void setZip(String zip) {
    this.zip = zip;
  }
}
application-dev.properties
logging.level.root=info
mail.smtp.host=mail.dev.com
mail.smtp.port=7777  
mail.smtp.user=test_dev 
application-prod.properties
logging.level.root=info
mail.smtp.host=mail.prod.com
mail.smtp.port=8888  
mail.smtp.user=prod_user
Run with profile prod
Run the application with prod profile set to active and then when the application is started, go to http://localhost:8080/details
mvn spring-boot:run -Dspring-boot.run.profiles=prod
Browser Output
Payment Server Version:= {Gateway=BankOfEngland, Currency=Pound, ChargePercentage=4} Mail Server SMTP Host: mail.prod.com SMTP Port:8888 ContactInfo From=admin Email=admin@bootng.com AddressInfo Street=1901 Palo Alto Avenue City=Palo Alto State=California Zip=950441
Run with profile dev
Stop the running application. And then restart with profile = dev
mvn spring-boot:run -Dspring-boot.run.profiles=dev
Browser Output
Payment Server Version:= {Gateway=BOA, Currency=USD, ChargePercentage=1} Mail Server SMTP Host: mail.dev.com SMTP Port:7777 ContactInfo From=admin Email=admin@bootng.com AddressInfo Street=1901 Palo Alto Avenue City=Palo Alto State=California Zip=950441
Download Source code
git clone git@github.com:bootng/spring-boot-references.git cd sping-boot-profiles mvn clean install mvn spring-boot:run -Dspring-boot.run.profiles=dev

Conclusion

This article shows different ways we can use Profiles in Application. We can see different values in the Controller output based on the profile. We can have multiple profiles active, but this article deals with only setting one profile at a time. Can you guess what will happen with this application and multiple profiles set active?

Spring Boot Profile Examples

This article show example of a Spring Boot Profile and how to use it. Spring Boot application can define multiple Profiles, and at a time we can have more than one Profile active. Activating a certain profile can let the Application use the profile-specific property values or profile-specific Beans. To use different values based on different Profiles, either we can use profile-specific properties files. Or we can also define beans under different Profiles.

Profile specific beans

In Spring Boot we can have Beans which are populated with different values based on the profile that is active. The following example shows a Configuration class PaymentProperties which contains a Bean PaymentProp defined under two profiles. For profile "dev" we are setting currency as USD but for profile "prod" we are setting currency as Pound.
@Profile at the @Bean
The following example shows how to use @Profile annotation at the method level. We have defined two methods(same PaymentProp Beans, different implementations under different Profile) inside the PaymentProperties class. Both methods are annotated with different Profiles. Essentially we have defined profile-specific beans.
@Configuration
public class PaymentProperties {

  @Profile("dev")
  @Bean(name="PaymentProp")
  public HashMap getPaymentServerDev() {
      HashMap paymentMethod = new HashMap<>();
      paymentMethod.put("Currency", "USD");
      paymentMethod.put("ChargePercentage", "1");
      paymentMethod.put("Gateway", "BOA");
      return paymentMethod;
   }
  
  
  @Profile("prod")
  @Bean(name="PaymentProp")
  public HashMap getPaymentServerProd() {
      HashMap paymentMethod = new HashMap<>();
      paymentMethod.put("Currency", "Pound");
      paymentMethod.put("ChargePercentage", "4");
      paymentMethod.put("Gateway", "BankOfEngland");
      return paymentMethod;
  }
  
}
Now When we load the bean, based on which profile is active, Spring Boot will load the corresponding Bean definition.

@Profile with @PropertySource

In this example, we have only one Class defined as MailSenderProperties. Based on the active profile spring boot will populate this class with values read from respective property files.
MailSenderProperties
The following class demonstrates how to use Profile to read profile based configuration files. In this case the MailSenderProperties class with be populated with values from the respective properties file.
@Component
@PropertySource("classpath:application-${spring.profiles.active}.properties")
public class MailSenderProperties {

  @Value("${mail.smtp.host}")
  private String smtpHost;

  @Value("${mail.smtp.port}")
  private Integer smtpPort;

  public String getSmtpHost() {
    return smtpHost;
  }

  public void setSmtpHost(String smtpHost) {
    this.smtpHost = smtpHost;
  }

  public Integer getSmtpPort() {
    return smtpPort;
  }

  public void setSmtpPort(Integer smtpPort) {
    this.smtpPort = smtpPort;
  }
}
Important Points
With Profile specific beans we have to make sure that the beans are available under the respective profiles, before using it. We can have multiple profiles active at a time so we can have multiple beans also populated. @Bean name is important as that is the name by which we can access the beans defined.

Further Reading


What is Spring Boot Profiles

Generally software applications, we need to be able to run it under different environments or under different setups. For example, say our application sends emails. For sending emails we need to configure SMTP servers with correct server URL, user, password etc. While developing we will generally have different SMTP servers credentials then the Production servers. Let's assume we have two different kinds of environments, dev- Development and prod-Production. So we would like to run the same code in dev and prod environments but with different configurations for email. Similarly we might have similar requirements for database, logs, security, etc, where we want to have different services/configurations plugged while in developing vs in productions. Spring Profiles helps to segregate our application configurations and make them available only in certain environments. 
In this article, we will dive into a situation where we would like to use different configurations in different environments. To achieve this high level we need two things,
1) Way to provide different configurations under different environments
2) Way to use environment-specific values in our app.
In the following example, we have two profiles and two property files. We have a java class MailSenderProperties which encapsulates the email configuration. Spring Boot will populate MailSenderProperties based on the profile that is active.

Profile and Properties files

Property file naming scheme
The property file is generally named by application HYPHEN PROFILENAME HYPHEN.properties.
application-{_profile_}.properties
We have two profiles (dev, prod) and two profile-specific property files. application-dev.properties application-prod.properties Now based on the profile we set active the property values would be read from the corresponding properties file.

Properties files

application-dev.properties
This is the property file for dev profile.
mail.smtp.host=mail.dev.com
mail.smtp.port=7777  
mail.smtp.user=test_dev 
application-prod.properties
This is the property file for prod profile.
mail.smtp.host=mail.prod.com
mail.smtp.port=8888  
mail.smtp.user=prod_user
application.properties
This is the common property file, which contains general configurations like logging level and also the active profile.
#Other configurations
spring.profiles.active=dev
logging.level.root=info

Mapping the Profile specific value to java class

MailSenderProperties
Java class to encapsulate the MailSender values, which are read from the application-PROFILE.properties file. We use the @PropertySource annotation and specify the respective property file that should be used by classpath:application-${spring.profiles.active}.properties
@Component
@PropertySource("classpath:application-${spring.profiles.active}.properties")
public class MailSenderProperties {

  @Value("${mail.smtp.host}")
  private String smtpHost;

  @Value("${mail.smtp.port}")
  private Integer smtpPort;

  public String getSmtpHost() {
    return smtpHost;
  }

  public void setSmtpHost(String smtpHost) {
    this.smtpHost = smtpHost;
  }

  public Integer getSmtpPort() {
    return smtpPort;
  }

  public void setSmtpPort(Integer smtpPort) {
    this.smtpPort = smtpPort;
  }
}

Setting Active Profile

We can set the active profile a number of ways. Some of the ways we need to change code to set the active profile. Here we will cover some fo the ways to set the active profile without changing code. 1) Set an active profile in the application.properties file ( dev is the active profile) spring.profiles.active=dev 2) set the active profile via an environment variable ( prod is the active profile) export spring_profiles_active=prod
Summary
  • Though using Spring Profile we can use a different set of properties under different circumstances
  • Spring profile can be set both programmatically and though environment variables
  • We can have more than one active profile settings at any time.
  • If we don't set any profile then Spring boot uses a profile called default profile.

Next Reading


Externalizing configuration properties

Spring Boot is developer-friendly and supports a number of features to increase productivity. One of them is externalizing configuration properties. Externalizing configuration properties means that all the configuration values are not hardcoded in the application and hence we can change the values as needed while deploying the application. Spring Boot supports a number of different ways to externalize properties and read them in the application.
We can have properties defined in various locations( different property files ) and various sources (property files, command line, System Properties, etc.), spring boot uses a specific order to read the values from those sources, which also enables us to override values. For example, we may provide some default values to the application, then while running it we might want to override some values.
The following are some of the places from where the application can read property values. The list is in descending priority. For example, property values passed though command-line argument will override Java system properties or default properties.
Property value priority order (Descending priority)
  • Command-line arguments.
  • Java System properties.
  • OS level environment variables.
  • @PropertySource annotations classes.
  • Application properties outside of your packaged jar.
  • Application properties packaged inside your jar.
  • Default properties.

Accessing properties values

Spring Boot provides multiple ways to access property values. The following are some of the ways. We will be using the bellow property file (office-address.properties) to demonstrate some of the ways to access the values defined in it.
office-address.properties
Property file which contains properties names and values. We will read this property to java classes by using @Value and @ConfigurationProperties
#Sample Property file
contact.from=admin
contact.fromEmail=admin@bootng.com
contact.fromPhone=Hello from bootng
contact.fromTwitter=@BootNGTweet

address.street=1901 Palo Alto Avenue
address.city=Palo Alto
address.state=California
address.zip=950441

Reading with @Value annotation

@Value
With @Value annotation, we can map a particular property to a java class field. Here we mapped different fields of the class AddressProperties to the properties in the office-address.properties by individual @Value annotations.
@Component
@PropertySource("classpath:office-address.properties")
@Validated
public class AddressProperties {
  @Value("${address.street}")
  private String street;

  @Value("${address.city}")
  private String city;

  @Value("${address.state}")
  private String state;

  @NotNull
  @Value("${address.zip}")
  private String zip;
}

Reading with @ConfigurationProperties annotation

@ConfigurationProperties
@Value is good when the properties are small in number. But say we want many properties to individual fields in the Java Class then we can use ConfigurationProperties. Spring will map the field name with the property name and will populate the value automatically. In the bellow example the filename twitterHandle does not match with the property fromTwitter. So with @ConfigurationProperties Spring boot will not be able to match the field with corresponding property and hence it would be null. To fix the issue we can use @Value("${contact.fromTwitter}") for the twitter field to populate it with @Value annotation.
@Component
@ConfigurationProperties(prefix = "contact")
@PropertySource("classpath:office-address.properties")
public class ContactProperties {

  private String from;

  private String fromEmail;

  @Value("${contact.fromTwitter}")
  private String twitterHandle;

  public String getFrom() {
    return from;
  }

}

Validating properties

@Validated Annotation
@Validated Annotation can be used to validate the field values. Spring Boot supports many validation rules, like NotNull, Email, NotEmpty, etc. Similar to the above class but now we have decorated the class with @Validated annotation and marked some of the fields with @NotNull and @Email validations. Doing so, if the values for these fields do not comfort to the validation rules defined, Spring Boot will throw expectation.
@Component
@ConfigurationProperties(prefix = "contact")
@PropertySource("classpath:office-address.properties")
@Validated
public class ContactProperties {

  @NotNull
  private String from;

  @Email
  private String fromEmail;

  @Value("${contact.fromTwitter}")
  private String twitterHandle;

  public String getFrom() {
    return from;
  }
}
Summary
  • We can use @Value annotation to map individual properties from the property file.
  • We can use @ConfigurationProperties to map all the fields of a class with respective properties from the property file.
  • With @ConfigurationProperties the field name in the class and property name should match.
  • With @ConfigurationProperties the prefix if provided is used to filter properties with matching name.
  • We can use both @Value and @ConfigurationProperties in the same class.
  • We can also validate the field values along with populating using @Validated annotation.

Introduction

This article show how to write a very simple Hello World Application in Spring. This application can be used as starting point for other applications.
We will go though the main components of the application, also code for the whole project is provided to download and play with it.

Technologies used

  • Java 11
  • Spring Boot 2.2.6.RELEASE
  • Maven 3.5.0
  • Eclipse IDE
This is a very simple Spring boot application with just one controller. The intention of the Application is to build a web app that when accessed will return a String message. This project is intended to help understand how to build a very simple Spring Application. So we are not touching other concepts like configuration, Profiles, etc.

Project Structure



Project code reference

The following paragraphs show important files for this sample project. Like the pom.xml file, HelloApplication.java (Spring Boot Application class) and the Controller class which is responsible for serving the request (HelloController.java)
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <artifactId>bootng-springboot-hello</artifactId>
 <version>1.0.0</version>
 <packaging>war</packaging>
 <name>Spring Boot Hello</name>
 <description>Spring Boot Hello Simple Application</description>
 <parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.2.6.RELEASE</version>
  <relativePath />
 </parent>
 <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  <java.version>1.8</java.version>
 </properties>
 <dependencies>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
 </dependencies>
 <build>
  <plugins>
   <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
     <addResources>true</addResources>
    </configuration>
    <executions>
     <execution>
      <goals>
       <goal>repackage</goal>
      </goals>
     </execution>
    </executions>
   </plugin>
  </plugins>
 </build>
</project>
Application Class
Spring Boot entry class that would be loaded and executed once the application boots up. It does not do much except that it has the annotation @SpringBootApplication to tell the spring boot framework that this is the entry point class. Also, it has @ComponentScan, so that Spring boot framework can scan and load any components from package com.bootng.
package com.bootng;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@ComponentScan({"com.bootng"})
@SpringBootApplication
public class HelloApplication {
  private static final Logger log = LoggerFactory.getLogger(HelloApplication.class);
  public static void main(String args[]) {
    log.info("about to call HelloApplication.run()");
    SpringApplication.run(HelloApplication.class, args);
    log.info("completed executing HelloApplication.run()");
  }
}
HelloController
Our only Controller class that is mapped to the path /hello and return a String as a response.
package com.bootng;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HelloController {
  @RequestMapping("/hello")
  public  @ResponseBody String hello() {
    return "Hello Spring Boot!";
  }
}

Run hello spring boot app

Build and Run Application
run the following command in the console to build the application and then run the application.
mvn clean install
mvn spring-boot:run
Console (Portion of the terminal logs)
INFO main c.b.HelloApplication:651 - No active profile set, falling back to default profiles: default 
INFO main o.s.b.w.e.t.TomcatWebServer:92 - Tomcat initialized with port(s): 8080 (HTTP)
INFO main o.a.c.h.Http11NioProtocol:173 - Initializing ProtocolHandler ["http-nio-8080"]
INFO main o.a.c.c.StandardService:173 - Starting service [Tomcat]
INFO main o.a.c.c.StandardEngine:173 - Starting Servlet engine: [Apache Tomcat/9.0.33]
INFO main o.s.b.w.e.t.TomcatWebServer:204 - Tomcat started on port(s): 8080 (http) with context path ''
Started HelloApplication in 1.384 seconds (JVM running for 1.716)
INFO main c.b.HelloApplication:18 - completed executing HelloApplication.run()
Access the application by
typing in the browser.
 http://localhost:8080/hello
We should be able to see the page returning the message from the controller.
Download source code
  • git clone https://github.com/bootng/spring-boot-references
  • cd bootng-springboot-hello
  • mvn install
  • mvn spring-boot:run

    Summary

    • This article shows how to build a sample web application from scratch.
    • This is a Maven-based project, similarly, we can have a Gradle based project also.
    • For the mvn install step, we need to be connected to the internet.
    • This is a simple web app that has only one request path mapped.
    • If we try with different paths then this App will show an error page.

    Introducing Spring Boot Initializer

    Spring Boot Initializer is a web app that helps in bootstrapping spring boot projects. Though the Spring Boot Initializer we can quickly provide dependencies, choose a Build tool like Maven, Gradle, etc, and generate the codes along with configurations. The following image shows spring boot Initializer web app.

    Initializer Web App
    Spring Boot Initializer Web App

    How to generate code

    To generate the code please follow the following steps
    • Go to https://start.spring.io/
    • Select project build tools (Maven, Gradle).
    • Select the language (Java, Kotlin, Groovy).
    • Select Spring Boot Version
    • Provide the meta-information like the artifact name, descriptions, etc.
    • Select Java version.
    • Select Packaging.
    • And also select the dependencies based on the need for the project.
    We can always add more dependencies, change the java version, etc. from the generated project code.
    This will allow the web app to create a sample project with sample codes and dependencies which will be downloaded to your computer. 

    Sample generated project.

    The following image shows a code structure for a sample web project generated.


    Demo of code generation.

    Following video shows a demo of code generation using the web app.

    References

    Summary

    • Spring Boot initializr web app can be used to bootstrap project.
    • The downloaded source code contains all dependencies and sample classes.
    • We can also start by cloning or forking an existing git repository.

    Spring Boot

    Spring Boot is an open-source framework to create Applications with minimum configurations. Spring boot provides a range of non-functional features that are common to applications like embedded servers, health checks, externalized configuration, CLI, etc. With Spring Boot, we can focus more on actual application logic and less on infrastructure. Some of the important features and concepts related to Spring Boot are listed below, which helps in getting started with Spring Boot.

    Entry Point of Application

    The entry point for any Spring Application is a class decorated with @SpringBootApplication annotation. This class contains the main method which will be invoked when the application boots.

    Component Scan

    Spring Boot uses a lot of annotation to increase developer productivity. For Applications to discover and initialize other components, Spring Boot uses @ComponentScan annotation. We can specify other Classes or packages that need to be scanned and initialized.

    Configuration

    Spring boot supports deferent ways of reading application configurations. We can provide configurations in YAML files or properties files or Java POJO Classes.

    Profiles

    Spring Boot supports Spring Profiles, which is a kind of different set of configuration values for different environments. For instance, we can have different database credentials for Production vs Test environments. Here we can put the database credentials values different under different Profiles.

    Build Tools

    Spring Boot supports different Build environments and technologies. For instance, we can use a maven to configure the build infrastructure, or we can also use Gradle, etc.

    Spring Boot Starters

    Spring boot can be used to develop a range of applications along with using different third party libraries. Spring boot starters provide pre-bundled dependencies for a particular type of application. In the Spring Boot Framework, all the starters follow a similar naming pattern: spring-boot-starter-*, where * denotes a particular type of application. For example if we want to develop an application based on Elastic Search we can use the starter spring-boot-starter-data-elasticsearch to bootstrap the application.

    Java Sorting with List and Array

    Array and List are some of the basic and very useful data structures. We often need to sort the data stored in Array and List. In this article, we examine some of the most common ways of sorting. Java provides Collections.sort class to sort Collections like List, Set, etc. Similarly, java also provides Arrays.sort() to sort Arrays. Both Collections.sort() and Arrays.sort() also takes Comparable instance which can be used to sort the data.

    List Sorting

    The following example shows different ways of sorting the Java List. We will be using Collections.sort() to sort the list. Collections class is part of the java.util package, and the sort method accepts a Comparator also. If we pass Comparator then the Comparator will be used to sort the objects in the collection. If Comparator is not passed then the natural ordering of the objects will be used to sort. Comparator.sort() takes a list of any objects provided that object implements a Comparable interface.
    Create List and Add Data
    Following code creates a list and adds data to it.
    List nameList = new ArrayList();
    nameList.add("Brazil");
    nameList.add("Canada");
    nameList.add("Japan");
    nameList.add("China");
    nameList.add("Australia");
    nameList.add("Russia");
    nameList.add("Nepal");
    nameList.add("Italy");
    nameList.add("Germany");
    Collections.sort
    The following code will sort the list using the natural ordering of the items in the list. For the above array, it will print Australia, Brazil, Canada, China, Germany, Italy, Japan, Nepal, Russia,
    printMessage("Sort List ......");
    Collections.sort(nameList);
    nameList.forEach(a -> nicePrint(a));
    
    Collection.sort with reverseOrder()
    Like above now we are sorting using Collections.sort, but also passing reverseOrder() comparator. It will print Russia, Nepal, Japan, Italy, Germany, China, Canada, Brazil, Australia,
    printMessage("Sort List Reverse Order .......");
    Collections.sort(nameList, Collections.reverseOrder());
    nameList.forEach(a -> nicePrint(a));
    Collection.sort using a custom Comparator
    Following code, sorts using Collections.sort and passed custom Comparator implemented using Lambda. It will print Australia, Brazil, Canada, China, Germany, Italy, Japan, Nepal, Russia,
    printMessage("Sort List using custom Comparator");
    Collections.sort(nameList, (k1, k2) -> (k1.compareTo(k2)));
    nameList.forEach(a -> nicePrint(a));
    Sort Part of the List
    We can also sort part of the list. For that, we can pass subList() of the actual list to the Collections.sort() method. The following code will print Brazil, Canada, Japan, China, Australia, Russia, Nepal, Italy, Germany. See the first 3 country names are sorted.
    Collections.sort(nameList.subList(0, 3));
    nameList.forEach(a -> nicePrint(a));

    Array Sorting

    The following example shows different ways of sorting the Java Array. We will be using Arrays.sort() to sort the array.
    Sort Array
    Sort the data array using Arrays.sort(). It will print the following It will print Australia, Brazil, Canada, China, Germany, Italy, Japan, Nepal, Russia.
    Arrays.sort(data);
    Sort Array in reverse order
    Sort in reverse order, bypassing reverseOrder() to the Arrays.sort() method. It will print Russia, Nepal, Japan, Italy, Germany, China, Canada, Brazil, Australia,
    Arrays.sort(data, Collections.reverseOrder());
    Sort Array by using a custom comparator
    Following code sorts data using Arrays.sort and a custom Comparator by using lambda.
    Arrays.sort(data, (k1, k2) -> (k1.compareTo(k2)));
    Sorting part of Array
    We can sort part of an array also, the following example shows how to sort only the first 3 items in the Array.
    Arrays.sort(data, 0, 3);
    Sorting Array using parallel sort.
    We can also sort the data by using parallelSort().
    Arrays.parallelSort(data);
    Summary
    • Collections.sort() can be used to sort a list of objects.
    • Collections.sort() uses BinarySearch algorithm.
    • Arrays.sort() uses Mergesort or Timsort algorithms to sort the data.
    • Collections.sort() and Arrays.sort() throws NullPointerException if data is null.
    • The object that we are sorting should implement java.langComparable interface.