Spring Boot example

Kommentare
MongoDB

In my first post I introduced a simple skeleton for bootstraping a Spring application. With the new release of the Spring Boot project this one gets obsolete and starting a Spring application gets much easier.

As before, the complete source code is available on GitHub.

To use the new Spring libraries it needs to configure the Maven POM file (there is Gradle support on the Spring Boot project site too). Last time this was simply done by a small dependency, now it needs some more XML code.

<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>
 <groupId>com.surpreso</groupId>
 <artifactId>spring-skeleton</artifactId>
 <version>0.0.3-SNAPSHOT</version>

 <!-- The packaging format, use war for web projects -->
 <packaging>jar</packaging>

 <!-- Inherit defaults from Spring Boot -->
 <parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>1.2.1.RELEASE</version>
 </parent>

 <dependencies>
  <!-- Spring Boot -->
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter</artifactId>
  </dependency>
  <!-- Spring Boot Test -->
  <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>
   </plugin>
  </plugins>
 </build>

</project>

The XML code doesn't look difficult, but lets go through it step for step. First we have to define the packaging format. As this application is no web project we will choose jar, otherwise war.

Now there comes the interesting part: Our project needs to inherite default values from the Spring Boot module to get well compiled. Running the project in an IDE worked without, but to build a jar containing all neccessary libraries you need to define the parent maven module.

Further more I added two dependencies to my project, starting with spring-boot-starter, which includes all Spring core libraries. To write unit and integration tests in a spring-fashion I added spring-boot-starter-test too.

The spring-boot-maven-plugin is needed to package all neccessary libraries into one uber-jar, which eases the deployment massively.


Now lets come to the fun part of this tutorial. At first we define a Spring configuration class.
Most Spring Boot tutorials skip this step and merge configuration and application class. Using our configurations in tests too, I seperated both.

package com.surpreso.spring_skeleton;

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class DefaultConfig {

}

The first annotation defines this class as a Spring configuration. The @EnableAutoConfiguration annotation enables the Spring Boot module to load default values and properties. With @ComponentScan we initiate Spring to search for auto wiring classes.

In the next step we create a very simple HelloWorld service which returns the current version of our application.

package com.surpreso.spring_skeleton;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class HelloWorldService {

 @Value("${app.version}")
 private String version;

 /**
  * @return the version
  */
 public String getVersion() {
  return version;
 }

}

The java code of the service class is very easy and there are only two spring relevant features used.
The @Compontent annotation tells Spring to auto wire the class. For simplicity I didn't define a interface before, which would be the enterprise way.
The @Value annotation introduces Spring to auto load the instance property version by the application property app.version. This property can be defined in a config file or by shell parameters.

In this project I choosed to read the properties from an YAML configuration file.

app:
  version: 0.3

For different application properties like database access information you can define further configuration files by naming them application-[profile].yml.
Before creating a test in the next steps, we define a application-test.yml configuration file to store a different version. Only being used in the test environment this file can use the src/test/resources folder.

app:
  version: 0.3-test

The following test simply checks if the HelloWorld serice loads the correct version from the properties.

package com.surpreso.spring_skeleton;

import static org.junit.Assert.assertTrue;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationContextLoader;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.surpreso.spring_skeleton.DefaultConfig;
import com.surpreso.spring_skeleton.HelloWorldService;

@ActiveProfiles("test")
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = DefaultConfig.class, loader = SpringApplicationContextLoader.class)
public class HelloWorldServiceTests {

 @Autowired
 HelloWorldService service;

 @Test
 public void test_getVersion() throws Exception {
  assertTrue(service.getVersion().endsWith("-test"));
 }

}

The test class has three annotations. The first one defines the profile being used to load properties and classes. The @RunWith annotation instructs junit to use the Spring test runner. Last the @ContextConfiguration defines the configuration classes and which loader is used.
The test itself is very straight forward, calls the getVersion method and checks if it ends with "-test". This should be true if the profile is loaded correctly.

Now we have tested our service, it is time to create an application which executes it. With Spring Boot this can be realized in a very elegant way.

package com.surpreso.spring_skeleton;

import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.Import;

@Import(DefaultConfig.class)
public class HelloWorldApplication implements CommandLineRunner {

 @Autowired
 private HelloWorldService helloWorldService;

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

 public void run(String... args) throws Exception {
  LoggerFactory.getLogger(getClass()).info(
    "This application works on version "
      + helloWorldService.getVersion());
 }

}

Not much code as you can see. The class simply implements the CommandLineRunner interface and executes the SpringApplication.run method by passing itself as parameter.
The @Import(DefaultConfig.class) annotation tells which configuration to us.
After loading the Spring framework, the run method gets executed and logs the version of the application, being delivered by our impressive service.
That's all! You can execute the application in your IDE or by maven and should see the Spring Boot splash output and the version of our project.


The last part of this tutorial covers the deployment of our project. The packaging of all libraries in one jar isn't trivial but Spring Boot offers a nice Maven plugin. All we need to execute is the maven package goal by running mvn package in the shell. The resulting jar file in the target folder has a size of about 5MB and contains all classes and libraries. To execute the jar we need to run the following command: java -jar target/spring-skeleton-0.0.3-SNAPSHOT.jar.

But there exists a second way to start our little application the Spring Boot way. Just execute mvn spring-boot:run in the shell and the app is launched but not packaged.

OK, that's all for today. Thanks to the Spring Boot developers for this nice project.

Kommentare :

  1. Awesome post! It helped me a lot. One little detail I noticed. Currently, your article says "[...] Only being used in the test environment this file can use the src/test/resource folder. [...].

    That should be src/test/resources (with s at the end), right?

    Thanks

    AntwortenLöschen
    Antworten
    1. Yes, you are right - fixed it.
      Thanks for the Feedback.

      Löschen

Hinweis: Nur ein Mitglied dieses Blogs kann Kommentare posten.