Tags

YAML

In the last post we used the application.properties config file, but Spring supports YAML for config too. So, the same config file from the last post (link in the end of the post) would be like this in a application.yml:

server:
    context-path: /
    port: 8081
spring:
    datasource:
        url: jdbc:h2:file:~/conscious_it
        username: sa
        password:
  • IMPORTANT: if there are both files, the priority is .properties

Configurations By Environment

  • Spring has the ability of being separated by environments. It means that I can have development and production configs separately and choose which to run dynamically. This feature is called Profile.
  • To choose which environment to execute, just pass the parameter -Dspring.profiles.active to JVM:
java -Dspring.profiles.active=dev -jar my_spring_boot_project.jar
  • This configuration would search the files:
application-dev.properties
application-dev.yml
  • The profile file pattern is:
application-{profile}.properties (ou yml)
  • In case of running in the IDE, just pass the parameter to the class that executes the SpringApplication.run
  • With Spring, it’s also possible set different implementations using the same parameter (spring.profiles.active) in the JVM. For this you need to use the Spring @Profile annotation.
    • Let’s suppose I have a UploadService interface and I want it to be AWS in production but for development I want it to be File. Using the annotation, it would look like this:

  • When injecting our UploadService, if the active profile is dev, the implementation will be FileService. If it’s prod, the implementation will be AWSService.

Overriding Spring Boot Configs

  • As seen in the previous post, Spring Boot automatically maps the current package and subpackages of that package. But what if I do not want to use this structure? If I want, instead of having a parent package of all: com.conscious.it, I want to have a package: com.conscious.it.config?
  • Well, it is necessary to override some Spring Boot settings by annotations:
    • @ComponentScan – Tells Spring where to look for other components, configurations, and services.
    • @EntityScan – Tells Spring where are the mapped entities.
    • @EnableJpaRepositories – Tells Spring where are the Spring Data repository classes.
  • Our project structure is now:
    • com.conscious.it.config – Where runs our SpringApplication.run and are our Spring settings.
    • com.conscious.it.controller – Our controllers, annotated with @Controller.
    • com.conscious.it.rest.controller – Our rest controllers, annotated with @RestController.
    • com.conscious.it.dao – Our DAOs, annotated with @Repository.
    • com.conscious.it.model – Our entities, annotated with @Entity.
    • com.conscious.it.service – Our service classes, annotated with @Service.
  • So, what we need to do is to map the Component packages, Entity packages and the Repository packages. Then the configuration would be:
@SpringBootApplication
@ComponentScan(basePackages= {
"com.conscious.it.controller",
"com.conscious.it.rest.controller",
"com.conscious.it.service"})
@EntityScan(basePackages = { "com.conscious.it.model"})
@EnableJpaRepositories(basePackages= { "com.conscious.it.dao"})

DevTools and Spring Loaded

  • Spring Boot DevTools is a module which aims to facilitate (even more) the development of the application. It disables the cache so that it does not impact when you see your changes and has an automatic restart when a resource is changed (Hot Swapping). It raises a LiveReload server and with each change of a file that is in Classpath, the server is immediately restarted.
  • To do this, just add the following dependency on the pom and all this will already be active:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <optional>true</optional>
</dependency>
  • The <optional>true</optional>, in other words, indicates that this dependency will not be used/placed in the final JAR. The <scope>provided</scope> also does this, but it’s a matter of semantics.
  • HOWEVER, sometimes we don’t want to always make a change and automatically restart the server. Sometimes we change a thing in a method and we wanted to see the change without restarting the server. For this, we have seen Spring Loaded in the post Programmer Utilities – Java Tools 01, but it is also possible to use in Spring Boot. To do this, simply change the Spring Boot Maven plugin to add the Spring Loaded dependency:
<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>springloaded</artifactId>
            <version>1.2.7.RELEASE</version>
        </dependency>
    </dependencies>
</plugin>
  • With this, it’s possible to use Spring Loaded and change your Java classes without restarting the server. Remember about using Spring Loaded:
    • The server must be started in DEBUG mode
    • Changing methods signature or creating new classes will need server restart.

Actuator

  • Spring Boot Actuator is a Spring Boot sub-project that adds services normally used in production and with little effort on your part. Basically, you add the library and it configs some endpoints with some info. Some of the main endpoints:
    • /metrics – Shows some application metrics, such as Threads started, Classes loaded, uptime, etc.
    • /health – Shows the application health status (example below)
    • /dump – Shows a thread dump, with info about the current threads.
    • /mappings – Shows all mapped paths.
    • /trace – Shows info of the last 100 requests.
    • /beans – Shows a complete list of all Spring beans of your application.
    • /env – Shows the properties and infos related to the environment.
  • Maven dependency:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-actuator</artifactId>
</dependency>
  • IMPORTANT: Some of these endpoints are accessible only by users configured with the ACTUATOR role. To configure the role, Spring Security is used. So we can just test, that is, ONLY FOR EXAMPLE, we will disable security by adding the following property in application.properties:
management.security.enabled=false

Example of a request to /health:

  • There are other endpoints that are associated depending on a configuration or lib used, such as /flyway and /liquibase, which show the database migrations applied.

Testing With Spring Boot

  • Spring Boot Test module already has some pretty useful libs such as JUnit, Mockito, AssertJ and Hamcrest (these two last ones help a lot to make the tests more readable and shorter).
  • It is possible to do all kinds of tests. Before, I’ll explain some important annotations:
    • @SpringBootTest – It loads a Spring context and include the ability of starting a container in a default port or configurated port by properties, but it’s recommended to use a random port. ie: @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
    • @ActiveProfiles – In the context of tests it is possible to activate a profile in the code. This ensures that your tests always run with the specific profiles. ie: @ActiveProfiles(“test”)
    • @WebMvcTest – Annotation that applies the minimum needed configuration to MVC tests
    • @MockBean – Injects a class mock
    • @LocalServerPort – Injects the used port to start a server on the test
  • So this would be a UserController integration test, which uses Thymeleaf and renders a view with the name of a user after the form data:

  • Complete UserControllerTest class: UserControllerTest.java
  • And next, would be a system test of the UserRestController, which in the case would return all registered users:

  • Note that in this case, the server runs on a random port and that it is possible to make real calls to the application. So it is HIGHLY RECOMMENDED to use a test profile.
  • Complete UserRestControllerTest class: UserRestControllerTest.java
  • APPENDIX: By default, the Spring context it’s not cleaned during tests on the class. That means that the object is not clean from a test to another. An instance can be the same of the next test. In case of database (assuming that it is configurated with spring.jpa.hibernate.ddl-auto=create), if the database is created once, it will keep it until the tests of that class ends. But sometimes we want it cleaned or recreated every test. For this we use the @DirtiesContext annotation, with the classMode parameter, which decides the context cleanup mode:
@DirtiesContext(classMode=ClassMode.BEFORE_EACH_TEST_METHOD)

JAR/WAR

  • As seen in the last post, Spring Boot Web brings an embedded Tomcat. So even with Web Container you do not have to worry. This is also good in a microservice structure, once the project is self contained.
  • But sometimes we do not want to use embedded Tomcat. But we already created the project as JAR. What to do?

How to migrate From Jar To War

  • In the pom.xml, you have to change the packaging to war:
<packaging>war</packaging>
  • Add on dependencies:
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <scope>provided</scope>
</dependency>
  • Create and put the ServletInitializer exactly on the same path of the class that invokes SpringApplication.run (let’s call it MainApplication)
package com.example;

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;

public class ServletInitializer extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(MainApplication.class);
    }

}
  • FYI: Put on pom.xml, inside <build> tag, the following parameter:
<finalName>myProject</finalName>
Advertisements