How to create Stand alone app?

With Spring Boot we can also create a stand-alone application, which does not need any web server or application server to run. In this article, we will go through a very simple Spring boot stand-alone application using the CommandLineRunner interface.
We will go through a very simple Spring Boot application trying to understand how CommandLineRunner works and what are the alternatives to CommandLineRunner interface like Application Runner. CommandLineRunner : This interface can be used to dictate that a class that implements this interface should be executed once the SpringApplication context loaded. This interface has a single method "run" which takes String array as arguments. ApplicationRunner : Similar to CommandLineRunner how it works, it also has only one method "run", which gets executed once the SpringBoot Context loads. The only difference between these two interfaces is argument types. the run method in ApplicationRunner accepts an array of ApplicationArguments whereas run method in CommandLineRunner accepts array or Strings.
CommandLineRunner.java
Definition of CommandLineRunner interface. Note that it is a Functional interface, meaning it has only one method.
@FunctionalInterface
public interface CommandLineRunner {
	/**
	 * Callback used to run the bean.
	 * @param args incoming main method arguments
	 * @throws Exception on error
	 */
	void run(String... args) throws Exception;
}

Technology Used

  • Java 11
  • Apache Maven 3.5.0
  • Spring Boot 2.2.6
  • Logback 1.2.3
  • Eclipse IDE

Code Structure


Application Details

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>jar</packaging>
	<name>Spring Boot Standalone App</name>
	<description>Spring Boot Hello Standalone 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</artifactId>
      </dependency>
	<dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<addResources>true</addResources>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>
HelloService
Our service Class defines three methods hello, bye, and onDestroy marked with @PreDestroy annotation.
package com.bootng;
import javax.annotation.PreDestroy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

@Service
public class HelloService {
  private static final Logger log = LoggerFactory.getLogger(HelloService.class);
  public String hello() {
    return "Hello Spring Boot!";
  }
  @PreDestroy
  public void onDestroy() throws Exception {
    log.info("Spring Container is destroyed!");
    bye();
  }
  public String bye() {
    String msg = "Bye..... Have a nice day!";
    log.info(msg);
    return msg;
  }
}
HelloApplication Class
Our HelloApplication Class implements CommandLineRunner interface. We inject the HelloService using @Autowired annotation. In the run method, we call the service.hello method.
package com.bootng;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
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 implements CommandLineRunner {
  private static final Logger log = LoggerFactory.getLogger(HelloApplication.class);
  @Autowired
  HelloService service;
  @Override
  public void run(String... args) throws Exception {
    log.info(service.hello());
  }
}

Running the application

Run the application by executing the following command
mvn spring-boot:run
Console Output
20-June-01 16:28:57:549 INFO main c.b.HelloApplication:651 - No active profile set, falling back to default profiles: default 20-June-01 16:28:57:844 INFO main c.b.HelloApplication:61 - Started HelloApplication in 0.64 seconds (JVM running for 0.872) 20-June-01 16:28:57:845 INFO main c.b.HelloApplication:26 - Hello Spring Boot! 20-June-01 16:28:57:846 INFO SpringContextShutdownHook c.b.HelloService:21 - Spring Container is destroyed! 20-June-01 16:28:57:847 INFO SpringContextShutdownHook c.b.HelloService:27 - Bye..... Have a nice day!
We can see the application will execute and terminate with messages like "Hello Spring Boot!" and Bye..."Have a nice day!"
First message is printed by run->service.hello() method as soon as the application starts.
The second message is somewhat special and is printed by invoking service.bye() by the Spring framework before the application exits.
Git Source Code
  • git clone https://github.com/siddharthagit/spring-boot-references
  • cd spring-boot-standalone-app
  • mvn clean install
  • mvn spring-boot:run

    Summary

    Using CommandLineRunner we can create a stand alone Spring Boot application
    We can use the @PreDestroy to call methods from service class before it is unloaded by Spring while exiting the application



    Testing Spring Boot App with JUnit 5 and Mockito

    Writing Unit Tests for an application is very important to make sure the software works as expected. JUnit 5 is the latest release of Junit 5 and it is already gaining popularity. In this article, we will walk through a simple Spring Boot Application and will write unit tests using Junit and Mockito.

    Purpose

    Before we dig into would like to give a broad overview of JUnit 5 and Mockito. Junit5 is the latest release of Junit, it is much different then Junit4, so many of the Junit4 specific annotations do not work with Junit 5. Mockito is a mocking framework and is very popular in the Opensource community. With Mockito we can mock an object or a method. For example in this article, we will be writing unit testing for the controller and we will mock the service layer.

    Application Details

    The Spring boot application we are building here is a simple App with one controller and one service class. The application creates rest endpoints (/blogs, /blogs/ID) through which we can get the list of blogs and specific blog details.

    Code Structure

    Spring Boot JUNIT5 Project Structure


    Code details

    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>com.bootng.springboot-rest</artifactId>
     <version>1.0.0-SNAPSHOT</version>
     <packaging>war</packaging>
     <name>bootngSpringboot  Rest</name>
     <description>bootng Springboot Rest</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>
      <!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
      <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-test</artifactId>
       <scope>test</scope>
      </dependency>
      <!-- junit 5 -->
      <dependency>
       <groupId>org.junit.jupiter</groupId>
       <artifactId>junit-jupiter-engine</artifactId>
       <scope>test</scope>
      </dependency>
      <dependency>
       <groupId>org.mockito</groupId>
       <artifactId>mockito-core</artifactId>
       <version>2.19.0</version>
       <scope>test</scope>
      </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>
    
    RestApplication.java
    Our main application class.
    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 RestApplication {
      private static final Logger log = LoggerFactory.getLogger(RestApplication.class);
      public static void main(String args[]) {
        log.info("about to call RestApplication.run()");
        SpringApplication.run(RestApplication.class, args);
        log.info("completed executing RestApplication.run()");
      }
    }
    
    BlogService.java
    Our service class which has three methods getBlogStory(String id), getBlogStory() and getBlogTags() respectively. Controller class which exposes the REST endpoints will call these methods.
    @Service
    public class BlogService {
      List category = Arrays.asList("Technical", "Travel", "Food", "Finance", "Entertainment");
      List stories = new ArrayList();
      {
        stories.add(new BlogStory("Java 11", "Technical", "Java 11 Blog"));
        stories.add(new BlogStory("Java 14", "Technical", "Java 14 Blog"));
        stories.add(new BlogStory("Asia Travel", "Travel", "Places to visit in Asia"));
        stories.add(new BlogStory("Europe Travel", "Travel", "Places to visit in Europe"));
        stories.add(new BlogStory("Japan Travel", "Travel", "Places to visit in Japan"));
        stories.add(new BlogStory("Asian Food", "Food", "Asian Food......"));
      }
    
      public BlogStory getBlogStory(String id) throws AppException{
        return stories.stream().filter(story -> id.equals(story.getId())).findAny().orElse(null);
      }
      public List getBlogStory() throws AppException {
        return stories;
      }
      public List getBlogTags() throws AppException{
        return category;
      }
    }
    BlogAPIController.java
    Controller class which creates two rest endpoints /blogs and /blog/ID. Both methods might return an error responses.
    @Controller
    @RequestMapping("/blogapi")
    public class BlogAPIController {
      private static final Logger log = LoggerFactory.getLogger(BlogAPIController.class);
      @Autowired
      BlogService blogService;
    
      @RequestMapping(value = {"/blogs"}, method = RequestMethod.GET,
          produces = MediaType.APPLICATION_JSON_VALUE)
      public @ResponseBody ResponseEntity> getBlogStories() {
        log.info("inside getBlogStories GET method");
        List blogStory = null;
        ResponseEntity> apiResponse;
        try {
          blogStory = blogService.getBlogStory();
          apiResponse = new ResponseEntity>(blogStory, HttpStatus.OK);
        } catch (AppException e) {
          apiResponse = new ResponseEntity>(blogStory, HttpStatus.INTERNAL_SERVER_ERROR);
          e.printStackTrace();
        }
        return apiResponse;
      }
      
      @RequestMapping(value = {"/blog"}, method = RequestMethod.GET,
          produces = MediaType.APPLICATION_JSON_VALUE)
      public @ResponseBody ResponseEntity  getBlogStory(@PathParam(value = "") String id) {
        log.info("inside blog GET method");
        BlogStory blogStory = null;
        ResponseEntity  apiResponse;
        try {
          blogStory = blogService.getBlogStory(id);
          if (blogStory == null) 
            apiResponse = new ResponseEntity(blogStory, HttpStatus.NOT_FOUND);
          else
            apiResponse = new ResponseEntity(blogStory, HttpStatus.OK);
        } catch (AppException e) {
          apiResponse = new ResponseEntity(blogStory, HttpStatus.INTERNAL_SERVER_ERROR);
          e.printStackTrace();
        }
         return apiResponse;
      }
    }
    BlogServiceTest.java
    In this Test class, we are testing the two methods of the Service class. We get an autowired instance of the BlogService class. We use the @ExtendWith annotation of JUnit5 . We also use the @ContextConfiguration annotation from Spring Boot to load the appropriate context.
    @ExtendWith(SpringExtension.class)
    @ContextConfiguration(classes = {BlogService.class})
    public class BlogServiceTest {
    
      @Autowired
      BlogService service;
    
      @Test
      public void test_getBlogStory() {
        List list;
        try {
          list = service.getBlogStory();
          Assertions.assertNotNull(list, "list should not be null");
        } catch (AppException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
    
      @Test
      public void test_getBlogStory_with_id() {
        BlogStory data;
        try {
          data = service.getBlogStory("Java_11");
          Assertions.assertNotNull(data, "data should not be null");
        } catch (AppException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
    }
    @ExtendWith(SpringExtension.class)
    @ContextConfiguration(classes = {BlogAPIController.class, BlogService.class})
    @TestInstance(TestInstance.Lifecycle.PER_CLASS)
    public class BlogAPIControllerTest {
      
      @Mock
      BlogService blogService;
      
      @InjectMocks
      private BlogAPIController controller;
      
      @BeforeAll
      public void setup() {
          MockitoAnnotations.initMocks(this);
      }
      
      @Test
      public void contextLoads() {}
      
      @Test
      public void test_getBlogStories() throws AppException {
        
        when(blogService.getBlogStory()).thenReturn(new ArrayList());
        
        ResponseEntity> object = controller.getBlogStories();
        
        Assertions.assertEquals(HttpStatus.OK, object.getStatusCode(), "OK Status");
        
      }
      
      @Test
      public void test_getBlogStory_not_found() throws AppException {
        
        when(blogService.getBlogStory("444")).thenReturn(null);
        
        ResponseEntity object = controller.getBlogStory("444");
        
        Assertions.assertEquals(HttpStatus.NOT_FOUND, object.getStatusCode(), "OK Status");
        
      }
    
    }
    BlogAPIControllerTest
    Our controller test class. In this class we use Mokito to inject a mocked BlogService, then we can use the stubbing method like "when" to return different results from the service class.
    @ExtendWith(SpringExtension.class)
    @ContextConfiguration(classes = {BlogAPIController.class, BlogService.class})
    @TestInstance(TestInstance.Lifecycle.PER_CLASS)
    public class BlogAPIControllerTest {
      
      @Mock
      BlogService blogService;
      
      @InjectMocks
      private BlogAPIController controller;
      
      @BeforeAll
      public void setup() {
          MockitoAnnotations.initMocks(this);
      }
     
      @Test
      public void contextLoads() {}
      
      @Test
      public void test_getBlogStories_success() throws AppException {
        
        when(blogService.getBlogStory()).thenReturn(new ArrayList());
        
        ResponseEntity> object = controller.getBlogStories();
        
        Assertions.assertEquals(HttpStatus.OK, object.getStatusCode(), "OK Status");
     }
      
      @Test
      public void test_getBlogStory_Not_found() throws AppException {
        
        when(blogService.getBlogStory("444")).thenReturn(null);
        
        ResponseEntity object = controller.getBlogStory("444");
        
        Assertions.assertEquals(HttpStatus.NOT_FOUND, object.getStatusCode(), "OK Status");
      }
    
    }

    Summary

    What is covered
    In this article, we saw how to write a simple Spring Boot Application. Write Unit tests and execute unit tests. Mock service classes.
    Source code and Build
    git clone https://github.com/bootng/spring-boot-references cd springboot-junit #build the application mvn install #run the tests mvn test

    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.