The following guide will focus on the Bootification of an existing spring based Java application. Every application has the potential to take a different Bootification journey depending on a number of different factors:
If a project is not using a build tool, then the recommendation is to use Gradle as the build tool, however if the project already uses either Maven or Gradle then it may be better to continue with the existing tool.
For Maven based projects, Spring Boot uses a Parent pom.xml
and Spring Boot Starter modules to provide necessary Spring dependencies and known versions of third-party dependencies that work well together. Maven will bring in transitive dependencies for you so it is always good to baseline the application's dependency tree before and after bootification. See Spring Boot Parent Pom v1.5.x for more detail: GitHub - spring-boot/pom.xml
pom.xml
mvn dependency:tree > mvn-dependency-tree-output.log
mvn-dependency-tree-output.log
to the code repositoryFor Gradle based projects, Spring Boot brings in a plugin which manages the dependencies of third party libraries. Dependency management plugin will bring in transitive dependencies. See Spring Boot Parent Pom v1.5.x for more detail: GitHub - spring-boot/pom.xml
build.gradle
gradle dependencies > gradle-dependency-tree-output.log
gradle-dependency-tree-output.log
to the code repositoryIf you are teasing out a slice of functionality from a monolith application then you should begin your journey by creating a new Spring Boot project with Spring Initializr. Spring Initializr is like a shopping cart for all the dependencies that you might need for you application.
src/main/java
src/main/resources/config
src/main/webapp/WEB-INF/
For Maven based projects, Spring Boot uses a parent pom.xml
for dependency and plugin management.
If the application is a stand alone project with no parent pom.xml
then add the Spring Boot Starter Parent section near the top of your pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.X.RELEASE</version>
</parent>
- If the application already contains a parent `pom.xml` and it will be the go-forward parent `pom.xml` then you can add a `<dependencyManagement>` section to your `pom.xml` and include the `spring-boot-dependencies` to use Spring Boot's dependency management.
- See: [Using Spring Boot without the Parent Pom](https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#using-boot-maven-without-a-parent)
```
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.X.RELEASE</version>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
```
For Gradle based projects, Spring Boot brings in a plugin which manages the dependencies of third party libraries. Dependency management plugin will bring in transitive dependencies
build.gradle
file buildscript {
ext {
springBootVersion = '1.5.10.RELEASE'
}
repositories {
maven {
credentials {
username mavenUsername
password mavenPassword
}
url 'https://repo.web.xyz.com/artifactory/Maven-Releases/'
}
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'org.springframework.boot'
- If the application has [multiple projects](https://www.petrikainulainen.net/programming/gradle/getting-started-with-gradle-creating-a-multi-project-build/) at the same level, then a root build.gradle describes elements that are common to all the projects. Since Spring Boot is likely to be managing the dependencies of all the child projects, it can be added in as a plugin to the child projects.
```
buildscript {
ext {
springBootVersion = '1.5.10.RELEASE'
}
repositories {
maven {
credentials {
username mavenUsername
password mavenPassword
}
url 'https://repo.web.xyz.com/artifactory/Maven-Releases/'
}
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
subprojects {
...
apply plugin: 'org.springframework.boot'
...
}
```
- Gradle Spring Boot plugin also tends to [repackage a jar](https://docs.spring.io/spring-boot/docs/current/reference/html/build-tool-plugins-gradle-plugin.html#build-tool-plugins-gradle-repackage-configuration) file. This is useful only for end applications and not for intermediate jar files. To prevent repacking for intermediate jars disable to boot repackage step the following way:
```
bootRepackage {
enabled = false
}
```
At this point you should be ready to add your first Spring Boot starter dependency and test case to your application.
For Maven, Add the spring-boot-starter-test
artifact:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
For Gradle:
testCompile('org.springframework.boot:spring-boot-starter-test')
- Create a parent package in `src/test/java` matching your package structure from `src/main/java` i.e. `com.companyname.appname`
- Add a Spring Application Context load test case and run it. You can use the following test as a baseline for ensuring the application has the necessary dependencies and is configured correctly. The test will attempt to fire up the application and create the Spring Application Context. The test case should fail at this point.
```java
package com.companyname.appname;
import static org.junit.Assert.assertNotNull;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTests {
@Autowired
ApplicationContext context;
@Test
public void contextLoads() {
assertNotNull(context);
}
}
```
One approach to creating a Spring Boot application is to add a java main method inside of a class annotated with @SpringBootApplication
. The @SpringBootApplication
convenience annotation encapsulates the @ComponentScan
, @Configuration
, @EnableAutoConfiguration
annotations. Additional information about @SpringBootApplication
can be found here: 18. Using the @SpringBootApplication annotation.
src/main/java
then create that now. For example, com.companyname.appname
Create a Spring Boot application class in the package created in the prior step.
package com.companyname.appname;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
The application will probably have many individual Spring dependencies i.e. spring-core, spring-jdbc, spring-context etc. The next step is to start removing explicit dependency versions and rely on Spring Boot’s starter modules and dependency management to import dependencies and include versions. One of the advantages of relying on Spring Boot as parent POM is that acts as a Bill of Materials for all the dependencies for that version of Spring Boot that work will together. Here is the catalog of Spring Boot starter modules: Spring Boot Reference Guide - Using Spring Boot Starter
<dependencyManagement>
section to your pom.xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.10.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
spring-boot-starter-*
modules<version>x.x.x</version>
NOTE: A compromise will most likely need to be made for some third-party dependencies that are not managed by Spring Boot's dependency management.No Class Def Found Exception
NOTE: If the application is a couple years old there is a good chance that it has accumulated some dependency debt. This is a good opportunity to only pull in dependencies that the application needs.Auto Configuration is one of the core tenants of Spring Boots opinionated framework. Spring Boot auto-configuration inspects the jar dependencies and attempts to configure the Spring application context on your behalf.
During the Bootification process you might find that by adding a jar dependency you cause an issue within your Spring Application context. The exception stack trace might indicate that there are multiple beans of the same type and Spring is unable to decipher which one to use.
If this occurs, then you should review the types of beans to see if they are related to JMS, DataSource, Web Services, etc.
debug=true
and restart the application. Spring Boot will log an Auto-Configuration report which might provide some more insight into the root cause of the issue.@SpringBootApplication(exclude = JmsAutoConfiguration.class)
or via the following property:
spring.autoconfigure.exlude=JmsAutoConfiguration
Spring Boot allows you to configure an executable war, executable jar or standalone war artifact.
web.xml
with a Java configuration class which includes @Bean
definitions for Servlets and Filters via ServletRegistrationBean
and FilterRegistrationBean
, respectively.
web.xml
to java config conversionSpring Boot has multitude of options to configure the applications environment variables. To reduce configuration drift, you should aim to reduce the number of environment specific files/profiles to the least common denominator.
@ImportResource
annotation to import it. If the xml file is small then this a good opportunity to replace with Java configuration.- If there are bean definitions in the Spring application context file that need to be environmentally friendly then this is good time to extract them into a Java Configuration class. For example, a `DataSource` bean should be extracted into Java configuration class annotated with `@Confguration`. This will provide an easy hook later to configure an embedded db locally and a Pivotal Platform user provided service when operating in the cloud profile. See the Spring-Music CF example application: [Spring Music](https://github.com/cloudfoundry-samples/spring-music)
@ConfigurationProperties
annotated class to house them.Spring Boot provides an easy to use spring-boot-starter-logging
module which will attempt to wire up your logging implementation based on the class path.
If your explicit definition of log level's is small then you may choose to get rid of your logback.xml
or log4j.properites
file all together and add the log levels to the application.[properties|yml
file
application.[properties|yml]
. For example, logging.level.org.apache.cxf=INFO
The spring-boot-maven-plugin
will, by default, add jars for running an embedded container in the lib-provided
folder within your jar or war artifact. If you are unable to deploy an executable artifact using an embedded servlet container then you must take an extra step to either remove the plugin completely or add the maven-war-plugin
to your pom.xml
explicitly.
Spring Boot combined with the Spring Boot Actuator Starter module enriches the telemetry capabilities of your application by providing a set of production ready endpoints to give you more insight into the health, performance, and environment configuration of your application. It also provides you with troubleshooting endpoints that allows you to trace http endpoints and generate heap dumps, emit custom metrics, and much more.