Springboot Learn by Example Sample
Springboot Learn by Example Sample
This is a Leanpub book. Leanpub empowers authors and publishers with the Lean Publishing
process. Lean Publishing is the act of publishing an in-progress ebook using lightweight tools and
many iterations to get reader feedback, pivot until you have the right book and build traction once
you do.
Appendix A : Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
About This Book
The SpringBoot : Lean by Example book will help you to understand what is SpringBoot, how
SpringBoot helps you to build Spring based applications quickly and easily and the inner workings
of SpringBoot using easy to follow examples.
What is SpringBoot?
How SpringBoot increases developer productivity?
How SpringBoot AutoConfiguration works behind the scenes?
Working with Databases using JdbcTemplate, MyBatis, JOOQ, Spring Data JPA
Working with MongoDB NoSQL database
Developing web applications using SpringBoot and Thymeleaf
Developing REST API using SpringBoot and Consuming from AngularJS Application
Securing web applications using SpringBoot and SpringSecurity
Monitoring SpringBoot applications with SpringBoot Actuator
Testing SpringBoot applications
i
About This Book ii
IntelliJ IDEA
NetBeans IDE
Build Tools
Maven
Gradle
Database Server
MySQL
PostgreSQL
Source Code
You can find the source code for this book at GitHub https://github.com/sivaprasadreddy/springboot-
learn-by-example
About Author
K. Siva Prasad Reddy is a Software Developer living in Hyderabad, India with more than 10
years of experience in developing enterprise applications using Java and JavaEE technologies. Siva
is a Sun Certified Java Programmer with deep expertise in building enterprise applications using
server-side technologies such as Java, JavaEE, Spring, Hibernate, MyBatis, JSF, PrimeFaces, and
WebServices (SOAP/REST).
Siva is also the author of Java Persistence with MyBatis 3 and PrimeFaces Beginners Guide
Packt Publishing books. He has worked with several Fortune 500 organizations and is passionate
about learning new technologies and their developments.
Siva shares the knowledge he has acquired on his blog at http://sivalabs.in. If you want to find out
more about his work, you can follow him on Twitter @sivalabs and GitHub https://github.com/sivaprasadreddy.
https://www.jetbrains.com/idea/
https://netbeans.org/
https://maven.apache.org/
http://gradle.org/
https://www.mysql.com/downloads/
http://www.postgresql.org/download/
https://github.com/sivaprasadreddy/springboot-learn-by-example
Book Revision History
08-July-2016 : Published First version.
16-July-2016 : Added following sections.
Added Section 9.3. Working with Multiple Databases
Added Sub-section Exposing JPA entities with bi-directional references through
RESTful services in Section 12.2. REST API using SpringMVC
30-July-2016 : Added new chapter. Chapter 16: Deploying SpringBoot Applications.
Running SpringBoot applications in production mode
Deploying SpringBoot application on Heroku
Running SpringBoot application on Docker
iii
Chapter 1: Introduction to SpringBoot
Spring is a very popular Java framework for building web and enterprise applications. Unlike
many other frameworks which focuses on only one area(web or persistence etc), Spring framework
provides a wide verity of features addressing the modern business needs via its portfolio projects.
Spring framework provides flexibility to configure beans in multiple ways such as XML, Annotations
and JavaConfig. With the number of features increased the complexity also gets increased and
configuring Spring applications becomes tedious and error-prone. Spring team created SpringBoot
to address the complexity of configuration.
But before diving into SpringBoot, we will take a quick look at Spring framework and see what kind
of problems SpringBoot is trying to address.
In this chapter we will cover:
Along with Spring framework there are many other Spring portfolio projects which helps to build
applications addressing modern business needs:
Spring Data: Simplifies data access from relational and NoSQL data stores.
Spring Batch: Provides powerful batch processing framework.
1
Chapter 1: Introduction to SpringBoot 2
There are many other interesting projects addressing various other modern application development
needs. For more information take a look at http://spring.io/projects.
In the initial days, Spring provides XML based approach for configuring beans. Later Spring
introduced XML based DSLs, Annotations and JavaConfig based approaches for configuring beans.
Let us take a quick look at how each of those configuration styles looks like.
XML based configuration
@Service
public class UserService
{
private UserDao userDao;
@Autowired
public UserService(UserDao dao){
this.userDao = dao;
}
...
...
}
@Repository
public class JdbcUserDao
{
private DataSource dataSource;
@Autowired
public JdbcUserDao(DataSource dataSource){
this.dataSource = dataSource;
}
...
...
}
@Configuration
public class AppConfig
{
@Bean
public UserService userService(UserDao dao){
return new UserService(dao);
}
@Bean
public UserDao userDao(DataSource dataSource){
return new JdbcUserDao(dataSource);
}
@Bean
Chapter 1: Introduction to SpringBoot 4
Spring provides many approaches for doing the same thing and we can even mix the approaches
as well like you can use both JavaConfig and Annotation based configuration styles in the same
application. That is a lot of flexibility and it is one way good and one way bad. People new to
Spring framework may gets confused about which approach to follow.
As of now the Spring team is suggesting to follow JavaConfig based approach as it gives
more flexibility. But there is no one-size fits all kind of solution. One has to choose the
approach based on their own application needs.
OK, now that you had a glimpse of how various styles of Spring bean configurations looks like.
Let us take a quick look at the configuration of a typical SpringMVC + JPA/Hibernate based web
application configuration looks like.
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.9.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.13</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.13</version>
Chapter 1: Introduction to SpringBoot 6
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.13</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.190</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.3.11.Final</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring4</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>
Chapter 1: Introduction to SpringBoot 7
</dependencies>
</project>
We have configured all our Maven jar dependencies to include Spring MVC, Spring Data JPA,
JPA/Hibernate, Thymeleaf and Log4j.
Step 2: Configure Service/DAO layer beans using JavaConfig.
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages="com.sivalabs.demo")
@PropertySource(value = { "classpath:application.properties" })
public class AppConfig {
@Autowired
private Environment env;
@Bean
public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer()
{
return new PropertySourcesPlaceholderConfigurer();
}
@Value("${init-db:false}")
private String initDatabase;
@Bean
public PlatformTransactionManager transactionManager()
{
EntityManagerFactory factory = entityManagerFactory().getObject();
return new JpaTransactionManager(factory);
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory()
{
LocalContainerEntityManagerFactoryBean factory =
new LocalContainerEntityManagerFactoryBean();
HibernateJpaVendorAdapter vendorAdapter =
new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(Boolean.TRUE);
vendorAdapter.setShowSql(Boolean.TRUE);
Chapter 1: Introduction to SpringBoot 8
factory.setDataSource(dataSource());
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan(env.getProperty("packages-to-scan"));
factory.afterPropertiesSet();
factory.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver());
return factory;
}
@Bean
public HibernateExceptionTranslator hibernateExceptionTranslator()
{
return new HibernateExceptionTranslator();
}
@Bean
public DataSource dataSource()
{
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
dataSource.setUrl(env.getProperty("jdbc.url"));
dataSource.setUsername(env.getProperty("jdbc.username"));
dataSource.setPassword(env.getProperty("jdbc.password"));
return dataSource;
}
@Bean
public DataSourceInitializer dataSourceInitializer(DataSource dataSource)
{
DataSourceInitializer dsInitializer = new DataSourceInitializer();
dsInitializer.setDataSource(dataSource);
ResourceDatabasePopulator dbPopulator = new ResourceDatabasePopulator();
dbPopulator.addScript(new ClassPathResource("data.sql"));
dsInitializer.setDatabasePopulator(dbPopulator);
dsInitializer.setEnabled(Boolean.parseBoolean(initDatabase));
return dsInitializer;
}
Chapter 1: Introduction to SpringBoot 9
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=admin
init-db=true
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=true
hibernate.hbm2ddl.auto=update
Create a simple sql script data.sql to populate sample data into USER table.
log4j.rootCategory=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p %t %c{2}:%L - %m%n
log4j.category.com.sivalabs=DEBUG
log4j.category.org.springframework=INFO
@Configuration
@ComponentScan(basePackages = { "com.sivalabs.demo"})
@EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter
{
@Bean
public TemplateResolver templateResolver() {
TemplateResolver templateResolver = new ServletContextTemplateResolver();
templateResolver.setPrefix("/WEB-INF/views/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("HTML5");
templateResolver.setCacheable(false);
return templateResolver;
}
@Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
return templateEngine;
}
@Bean
public ThymeleafViewResolver viewResolver() {
ThymeleafViewResolver thymeleafViewResolver =
new ThymeleafViewResolver();
thymeleafViewResolver.setTemplateEngine(templateEngine());
thymeleafViewResolver.setCharacterEncoding("UTF-8");
return thymeleafViewResolver;
Chapter 1: Introduction to SpringBoot 11
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
registry.addResourceHandler("/resources/**")
.addResourceLocations("/resources/");
}
@Bean(name = "messageSource")
public MessageSource configureMessageSource()
{
ReloadableResourceBundleMessageSource messageSource =
new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:messages");
messageSource.setCacheSeconds(5);
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
}
Create messages.properties file in src/main/resources folder and add the following property.
app.title=SpringMVC JPA Demo (Without SpringBoot)
Step 4: Register Spring MVC FrontController servlet DispatcherServlet.
Prior to Servlet 3.x specification we have to register Servlets/Filters in web.xml. Since Servlet 3.x
specification we can register Servlets/Filters programatically using ServletContainerInitializer.
Spring MVC provides a convenient class AbstractAnnotationConfigDispatcherServletInitializer
to register DispatcherServlet.
Chapter 1: Introduction to SpringBoot 12
@Override
protected Class<?>[] getServletConfigClasses()
{
return new Class<?>[] { WebMvcConfig.class };
}
@Override
protected String[] getServletMappings()
{
return new String[] { "/" };
}
@Override
protected Filter[] getServletFilters() {
return new Filter[]{ new OpenEntityManagerInViewFilter() };
}
}
@Entity
public class User
{
@Id @GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String name;
public User()
{
}
If you dont understand what is JpaRepository dont worry. We will learn more about Spring Data
JPA in Chapter 9: Working With JPA in detail.
Step 6: Create a SpringMVC Controller
Create a SpringMVC controller to handle URL / and render list of users.
@Controller
public class HomeController
{
@Autowired UserRepository userRepo;
@RequestMapping("/")
public String home(Model model)
{
model.addAttribute("users", userRepo.findAll());
return "index";
}
}
Chapter 1: Introduction to SpringBoot 14
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8"/>
<title>Home</title>
</head>
<body>
<h2 th:text="#{app.title}">App Title</h2>
<table>
<thead>
<tr>
<th>Id</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr th:each="user : ${users}">
<td th:text="${user.id}">Id</td>
<td th:text="${user.name}">Name</td>
</tr>
</tbody>
</table>
</body>
</html>
We are all set now to run the application. But before that we need to download and configure the
server like Tomcat or Jetty or Wildfly etc in your IDE. You can download Tomcat 8 and configure in
your favourite IDE, run the application and point your browser to http://localhost:8080/springmvc-
jpa-demo. You should see the list of users details in a table.
Chapter 1: Introduction to SpringBoot 15
Users List
YayWe did it. But wait..Isnt it too much work to just show a list of user details pulled from a
database table?
Let us be honest and fair. All this configuration is not just for this one use-case. This configuration is
basis for rest of the application also. But again, this is too much of work to do if you want to quickly
get up and running. Another problem with it is, assume you want to develop another SpringMVC
application with similar technical stack? Well, you copy-paste the configuration and tweak it. Right?
But remember one thing: if you have to do the same thing again and again, you should find an
automated way to do it.
Apart from writing the same configuration again and again, do you see any other problems
here?
Well, let me list our what are the problems I am seeing here.
1. You need to hunt for all the compatible libraries for the specific Spring version and configure
them.
2. 95% of the times we configure the DataSource, EntitymanagerFactory, TransactionManager
etc beans in the same way. Wouldnt it be great if Spring can do it for me automatically.
3. Similarly we configure SpringMVC beans like ViewResolver, MessageSource etc in the same
way most of the times. If Spring can automatically do it for me that would be awesome.
Imagine, what if Spring is capable of configuring beans automatically? What if you can customize
the automatic configuration using simple customizable properties? For example, instead of mapping
DispatcherServlet url-pattern to / you want to map it to /app/. Instead of putting thymeleaf views
in /WEB-INF/views folder you may want to place them in /WEB-INF/templates/ folder.
So basically you want Spring to do things automatically but provide the flexibility to override the
default configuration in a simpler way?
Chapter 1: Introduction to SpringBoot 16
Well, you are about to enter into the world of SpringBoot where your dreams come true!!!
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.6.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
Chapter 1: Introduction to SpringBoot 17
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
</project>
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=admin
spring.datasource.initialize=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
you can copy the same data.sql file into src/main/resources folder.
Step 3: Create a JPA Entity and Spring Data JPA Repository Interface for the entity.
Create User.java, UserRepository.java and HomeController.java same as in springmvc-jpa-demo
application.
Step 4: Create Thymeleaf view to show list of users
Copy /WEB-INF/views/index.html that we created in springmvc-jpa-demo application into src/-
main/resources/templates folder in our new project.
Step 5: Create SpringBoot EntryPoint Class.
Create a Java class Application.java with main method as follows:
Chapter 1: Introduction to SpringBoot 18
@SpringBootApplication
public class Application
{
public static void main(String[] args)
{
SpringApplication.run(Application.class, args);
}
}
Now run Application.java as a Java Application and point your browser to http://localhost:8080/.
You should see the list of users in table format.
Ok ok, I hear you are shouting What is going on???.
First thing to observe is we are using some dependencies named like spring-boot-starter-*.
Remember I said 95% of the times I use same configuration. So when you add spring-
boot-starter-web dependency by default it will pull all the commonly used libraries while
developing Spring MVC applications such as spring-webmvc, jackson-json, validation-api
and tomcat.
We have added spring-boot-starter-data-jpa dependency. This pulls all the spring-data-
jpa dependencies and also adds Hibernate libraries because majority of the applications use
Hibernate as JPA implementation.
2. Auto Configuration
Not only the spring-boot-starter-web adds all these libraries but also configures the
commonly registered beans like DispatcherServlet, ResourceHandlers, MessageSource etc
beans with sensible defaults.
We also added spring-boot-starter-thymeleaf which not only adds the thymeleaf library
dependencies but also configures ThymeleafViewResolver beans as well automatically.
We havent defined any of the DataSource, EntityManagerFactory, TransactionManager
etc beans but they are automatically gets created. How?
If we have any in-memory database drivers like H2 or HSQL in our classpath then SpringBoot
will automatically creates an in-memory DataSource and then registers EntityManagerFac-
tory, TransactionManager beans automatically with sensible defaults.
But we are using MySQL, so we need to explicitly provide MySQL connection details. We
have configured those MySQL connection details in application.properties file and SpringBoot
creates a DataSource using these properties.
Chapter 1: Introduction to SpringBoot 19
The most important and surprising thing is we have created a simple Java class annotated
with some magical annotation @SpringApplication having a main method and by running
that main we are able to run the application and access it at http://localhost:8080/.
Where is the servlet container comes from?
We have added spring-boot-starter-web which pull the spring-boot-starter-tomcat auto-
matically and when we run the main() method it started tomcat as an embedded container so
that we dont have to deploy our application on any externally installed tomcat server.
By the way have you observe that our packaging type in pom.xml is jar not war. Wonderful!
Ok, but what if I want to use Jetty server instead of tomcat? Simple, exclude spring-boot-
starter-tomcat from spring-boot-starter-web and include spring-boot-starter-jetty. Thats
it.
1.4. Summary
In this chapter we had a quick overview of various Spring configuration styles and understand the
complexity of configuring Spring applications. Also, we had a quick look at SpringBoot by creating
a simple web application.
In next chapter we will take a more detailed look at SpringBoot and how we can create SpringBoot
applications in different ways.
Chapter 2: Getting Started with
SpringBoot
In the previous chapter we had a quick look at how we can develop a typical SpringMVC +
JPA(Hibernate) based web application using plain SpringMVC and Spring ORM modules. We have
discussed about the complexity of configuring the Spring based applications. And then we took a
quick look at how to develop the same web application using SpringBoot in a much easier way. But
we didnt go in-detail about SpringBoot.
In this chapter we are going to take a more detailed look into SpringBoot and what are the features
SpringBoot offers.
In this chapter we will cover:
What is SpringBoot?
Creating SpringBoot application
IDE and Build Tools support
Fat jar using SpringBoot Maven Plugin
SpringBoot starters
SpringBoot AutoConfiguration
Elegant Configuration Management
SpringBoot Actuator
Easy to use Embedded Servlet container support
20
Chapter 2: Getting Started with SpringBoot 21
SpringBoot starters
SpringBoot offers many starter modules to get started quickly with many of the commonly used
technologies like SpringMVC, JPA, MongoDB, Spring Batch, SpringSecurity, Solr, ElasticSearch
etc. These starters are pre-configured with the most commonly used library dependencies so that
we dont have to search for the compatible library versions and configure them manually.
For ex: spring-boot-starter-data-jpa starter module includes all the dependencies required to use
Spring Data JPA along with Hibernate library dependencies as Hibernate is the most commonly
used JPA implementation.
You can find list of all the SpringBoot starters that comes out-of-the-box in official documentation
at Starter POMs
SpringBoot AutoConfiguration
SpringBoot addresses the Spring applications needs complex configuration problem by elimi-
nating the need to manually configuring the boilerplate configuration by using AutoConfiguration.
SpringBoot takes opinionated view of the application and configures various components automat-
ically by registering beans based on various criteria.
The criteria can be:
etc.
For example:
If you have spring-webmvc dependency in your classpath SpringBoot assumes you are trying to
build a SpringMVC based web application and automatically tries to register DispatcherServlet if
it is not already registered by you.
If you have any Embedded database driver in classpath like H2 or HSQL and if you havent con-
figured any DataSource bean explicitly then SpringBoot will automatically register a DataSource
bean using in-memory database settings.
We will learn more about the AutoConfiguration in further chapters in detail.
http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#using-boot-starter-poms
Chapter 2: Getting Started with SpringBoot 22
SpringBoot Actuator
Being able to get the various details of an application running in production is very crucial to many
applications. SpringBoot Actuator provides a wide variety of such production ready features without
requiring to write much code.
Some of the Spring Actuator features are:
Now you can extract the downloaded zip file and import into your favorite IDE.
Select File -> New -> Other -> Spring -> Spring Starter Project -> Next
You will see the wizard which looks similar to Spring Initializer.
Chapter 2: Getting Started with SpringBoot 24
Enter the project details, click Next and select the starters and click Finish.
Chapter 2: Getting Started with SpringBoot 25
The SpringBoot project will be created and automatically imported into STS IDE as well.
Select File -> New -> Project -> Spring Initializer -> Next
Chapter 2: Getting Started with SpringBoot 26
Enter the project details, click Next and select the starters, click Next and enter Project Name
and click Finish.
Spring support comes out-of-the-box only in commercial Intellij IDEA Ultimate Edition,
but not in Community Edition which is free. But if you want to use Intellij IDEA
Community Edition then you can generate the project using Spring Initializer and import
into Intellij IDEA as Maven/Gradle project.
There are some other options to quickly start using SpringBoot by using Spring Boot CLI
and SDKMAN. You can find more details at Installing Spring Boot.
Now you have created a SpringBoot Maven based project with web starter.
Let us explore what is contained in the generated application.
Step 1: First, let us take a look at pom.xml file.
<groupId>com.sivalabs</groupId>
<artifactId>springboot-basic</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>springboot-basic</name>
<parent>
<groupId>org.springframework.boot</groupId>
https://github.com/AlexFalappa/nb-springboot
http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#getting-started-installing-spring-boot
Chapter 2: Getting Started with SpringBoot 27
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.6.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</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>
</plugin>
</plugins>
</build>
</project>
1. First thing to note here is our springboot-basic maven module is inheriting from spring-
boot-starter-parent module.
By inheriting from spring-boot-starter-parent module we will automatically get the follow-
ing benefits:
We only need to specify the springboot version once in parent module configuration. We
dont need to specify the version for all the starter dependencies and other supporting
libraries.
To see all the list of supporting libraries see the pom.xml of org.springframework.boot:spring-
boot-dependencies:1.3.6.RELEASE maven module.
The parent module spring-boot-starter-parent already included the most commonly used
Chapter 2: Getting Started with SpringBoot 28
package com.sivalabs.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringbootBasicApplication
{
public static void main(String[] args)
{
SpringApplication.run(SpringbootBasicApplication.class, args);
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Configuration
@EnableAutoConfiguration
@ComponentScan
public @interface SpringBootApplication {
....
....
}
package com.sivalabs.demo;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HomeController
{
@RequestMapping("/")
public String home(Model model) {
return "index.html";
}
}
Chapter 2: Getting Started with SpringBoot 30
This is a simple SpringMVC controller with one request handler method for URL / which returns
the view name index.html.
Step 3: Create a HTML view index.html
By default SpringBoot serves the static content from src/main/public/ and src/main/static/ direc-
tories. So create index.html in src/main/public/ as follows:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Home</title>
</head>
<body>
<h2>Hello World!!</h2>
</body>
</html>
Now from your IDE run the SpringbootBasicApplication.java main() method as stand-alone
Java class which will start the embedded tomcat server on port 8080 and point your browser to
http://localhost:8080/.
You should be able to see the response Hello World!!.
You can also run the SpringBoot application using spring-boot-maven-plugin goal as follows:
mvn spring-boot:run
Now you can see two interesting files in target directory, springboot-basic-1.0-SNAPSHOT.jar and
springboot-basic-1.0-SNAPSHOT.jar.original.
The springboot-basic-1.0-SNAPSHOT.jar.original will contain only the compiled classes and
classpath resources.
But if you look into springboot-basic-1.0-SNAPSHOT.jar you can find the following:
Chapter 2: Getting Started with SpringBoot 31
We can create self contained deployment unit for jar type modules using plugins like
maven-shade-plugin which packages all the dependent jars classes into single jar file.
But Spring Boot follows a different approach which allows to nest jars directly with in
our SpringBoot application jar file. You can read more about it here The executable jar
format
Now you can run the application using the following command:
java -jar springboot-basic-1.0-SNAPSHOT.jar
buildscript {
repositories {
jcenter()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.3.6.RELE\
ASE")
}
}
repositories {
jcenter()
http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#executable-jar
Chapter 2: Getting Started with SpringBoot 32
dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
testCompile("org.springframework.boot:spring-boot-starter-test")
}
Now you can run the application using gradle bootRun or you can use gradle build command
which generates the fat jar in build/libs directory.
Maven or Gradle?
In Java world Maven and Gradle are two most popular build tools. Maven was released
in 2004 and is being used widely by lot of developers. Gradle was released in 2012 which is
more powerful and easy to customize for the modern projects complex build process needs.
As Maven is still the most commonly used build tool we will be using Maven through
out the book. However you can find the Gradle build scripts in the book sample code for
each of the modules.
So, you can use either Maven or Gradle. Choice is yours!!
2.3. Summary
Now that you know how to create a simple SpringBoot application and run it. But you want to
understand the magic behind the SpringBoots AutoConfiguration. But before that you should know
about Springs @Conditional feature based on which all the SpringBoots AutoConfiguration magic
depends.
https://github.com/sivaprasadreddy/springboot-learn-by-example
Chapter 3: SpringBoot Behind the
scenes
In the previous chapter we have learned how to create a SpringBoot application in various
ways. SpringBoot makes developing Spring based applications very easily using its powerful
AutoConfiguration mechanism. But it may not be still clear how SpringBoot is actually working
behind the scenes.
In this chapter we will cover:
33
Chapter 3: SpringBoot Behind the scenes 34
@Configuration
public class AppConfig
{
@Bean
@Profile("DEV")
public DataSource devDataSource() {
...
}
@Bean
@Profile("PROD")
public DataSource prodDataSource() {
...
}
}
Then you can specify the active profile using System Property -Dspring.profiles.active=DEV
This approach works for simple cases like enable or disable bean registrations based on activated
profiles. But if you want to register beans based on some conditional logic then the Profiles approach
itself is not sufficient.
To provide much more flexibility for registering Spring beans conditionally, Spring 4 introduced the
concept of @Conditional. By using @Conditional approach you can register a bean conditionally
based on any arbitrary condition.
For example, you may want to register a bean when:
These are just a few examples only and you can have any condition you want.
Let us take a look at how Springs @Conditional works.
We may want to enable only one of JdbcUserDAO and MongoUserDAO based on a System
Property say dbType.
If the application is started using java -jar myapp.jar -DdbType=MySQL then we want to enable
JdbcUserDAO, otherwise if the application is started using java -jar myapp.jar -DdbType=MONGO
we want to enable MongoUserDAO.
Suppose we have UserDAO interface and JdbcUserDAO, MongoUserDAO implementations as
follows:
Now we can configure both JdbcUserDAO and MongoUserDAO beans conditionally using
@Conditional as follows:
@Configuration
public class AppConfig
{
@Bean
@Conditional(MySQLDatabaseTypeCondition.class)
public UserDAO jdbcUserDAO(){
return new JdbcUserDAO();
}
@Bean
@Conditional(MongoDBDatabaseTypeCondition.class)
public UserDAO mongoUserDAO(){
Chapter 3: SpringBoot Behind the scenes 37
Now if we run the application like java -jar myapp.jar -DdbType=MYSQL then only JdbcUser-
DAO bean will be registered.
But if you set the System property like -DdbType=MONGODB then only MongoUserDAO bean
will be registered.
Now that we have seen how to conditionally register a bean based on System Property.
} catch (ClassNotFoundException e) {
return true;
}
}
}
We just have seen how to register beans conditionally based on presence/absence of a class in
classpath.
Now we can use the @DatabaseType annotation on our bean definitions as follows:
@Configuration
@ComponentScan
public class AppConfig
{
@DatabaseType("MYSQL")
public UserDAO jdbcUserDAO(){
return new JdbcUserDAO();
}
@Bean
@DatabaseType("MONGO")
public UserDAO mongoUserDAO(){
return new MongoUserDAO();
}
}
Here we are getting the metadata from DatabaseType annotation and checking against the System
Property dbType value to determine whether to enable or disable the bean registration.
We have seen good number of examples to understand how we can register beans conditionally
using @Conditional annotation.
SpringBoot extensively uses @Conditional feature to register beans conditionally based on various
criteria. You can find various Condition implementations that SpringBoot uses in org.springframework.boot.autoc
package of spring-boot-autoconfigure-{version}.jar.
Now that we come to know about how SpringBoot uses @Conditional feature to conditionally
check whether to register a bean or not.
But what exactly triggers the auto-configuration mechanism? This is what we are going to look at
in next section.
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application
{
@Configuration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })
public class DataSourceAutoConfiguration {
...
...
@Conditional(DataSourceAutoConfiguration.EmbeddedDataSourceCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import(EmbeddedDataSourceConfiguration.class)
protected static class EmbeddedConfiguration {
@Configuration
@ConditionalOnMissingBean(DataSourceInitializer.class)
protected static class DataSourceInitializerConfiguration {
@Bean
public DataSourceInitializer dataSourceInitializer() {
return new DataSourceInitializer();
}
Chapter 3: SpringBoot Behind the scenes 42
@Conditional(DataSourceAutoConfiguration.NonEmbeddedDataSourceCondition.clas\
s)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
protected static class NonEmbeddedConfiguration {
@Autowired
private DataSourceProperties properties;
@Bean
@ConfigurationProperties(prefix = DataSourceProperties.PREFIX)
public DataSource dataSource() {
DataSourceBuilder factory = DataSourceBuilder
.create(this.properties.getClassLoader())
.driverClassName(this.properties.getDriverClassName())
.url(this.properties.getUrl()).username(this.properties.getU\
sername())
.password(this.properties.getPassword());
if (this.properties.getType() != null) {
factory.type(this.properties.getType());
}
return factory.build();
}
}
...
...
@Configuration
@ConditionalOnProperty(prefix = "spring.datasource", name = "jmx-enabled")
@ConditionalOnClass(name = "org.apache.tomcat.jdbc.pool.DataSourceProxy")
@Conditional(DataSourceAutoConfiguration.DataSourceAvailableCondition.class)
@ConditionalOnMissingBean(name = "dataSourceMBean")
protected static class TomcatDataSourceJmxConfiguration {
@Bean
public Object dataSourceMBean(DataSource dataSource) {
....
....
}
}
...
...
}
Chapter 3: SpringBoot Behind the scenes 43
@ConfigurationProperties(prefix = DataSourceProperties.PREFIX)
public class DataSourceProperties
implements BeanClassLoaderAware, EnvironmentAware, InitializingBean {
With this configuration all the properties that starts with spring.datasource.* will be automatically
binds to DataSourceProperties object.
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=secret
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
You can also see some inner classes and bean definition methods that are annotated with Spring-
Boots Conditional annotations such as @ConditionalOnMissingBean, @ConditionalOnClass
and @ConditionalOnProperty etc. These bean definitions will be registered in ApplicationContext
only if those conditions are matched.
You can also explore many other AutoConfiguration classes in spring-boot-autoconfigure-{version}.jar
such as
org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
Chapter 3: SpringBoot Behind the scenes 44
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration
etc.
3.3. Summary
Now that we have an understanding of how SpringBoot auto-configuration works by using various
AutoConfiguration classes along with @Conditional features.
In next chapter, we will look into how to create our own Custom SpringBoot Starter.
Chapter 4: Creating Custom
SpringBoot Starter
SpringBoot provides lot of starter modules to get up and running quickly. SpringBoots auto-
configure mechanism takes care of configuring SpringBeans on our behalf based on various criteria.
In addition to the springboot starters that comes out-of-the-box provided by Core Spring Team, we
can also create our own starter modules.
In this post we will look into how to create a custom SpringBoot starter. To demonstrate it we are
going to create twitter4j-spring-boot-starter which will auto-configure Twitter4J beans.
To accomplish this, we are going to create:
<groupId>com.sivalabs</groupId>
<artifactId>spring-boot-starter-twitter4j</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
45
Chapter 4: Creating Custom SpringBoot Starter 46
<name>spring-boot-starter-twitter4j</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<twitter4j.version>4.0.3</twitter4j.version>
<spring-boot.version>1.3.6.RELEASE</spring-boot.version>
</properties>
<modules>
<module>twitter4j-spring-boot-autoconfigure</module>
<module>twitter4j-spring-boot-starter</module>
<module>twitter4j-spring-boot-sample</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.twitter4j</groupId>
<artifactId>twitter4j-core</artifactId>
<version>${twitter4j.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
In this pom.xml we are defining the SpringBoot and Twitter4j versions in section so that we dont
need to specify versions all over the places.
<parent>
<groupId>com.sivalabs</groupId>
<artifactId>spring-boot-starter-twitter4j</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
Chapter 4: Creating Custom SpringBoot Starter 48
<dependency>
<groupId>org.twitter4j</groupId>
<artifactId>twitter4j-core</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
Note that we have specified twitter4j-core as optional dependency because twitter4j-core should
be added to the project only when twitter4j-spring-boot-starter is added to the project.
package com.sivalabs.spring.boot.autoconfigure;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
@ConfigurationProperties(prefix= Twitter4jProperties.TWITTER4J_PREFIX)
public class Twitter4jProperties {
@NestedConfigurationProperty
private OAuth oauth = new OAuth();
twitter4j.debug=true
twitter4j.oauth.consumer-key=your-consumer-key-here
twitter4j.oauth.consumer-secret=your-consumer-secret-here
twitter4j.oauth.access-token=your-access-token-here
twitter4j.oauth.access-token-secret=your-access-token-secret-here
Here comes the key part of our starter. Twitter4jAutoConfiguration configuration class contains
the bean definitions that will be automatically configured based on some criteria.
What is that criteria?
If twitter4j.TwitterFactory.class is on classpath
If TwitterFactory bean is not already defined explicitly
package com.sivalabs.spring.boot.autoconfigure;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import twitter4j.Twitter;
import twitter4j.TwitterFactory;
import twitter4j.conf.ConfigurationBuilder;
@Configuration
@ConditionalOnClass({ TwitterFactory.class})
@EnableConfigurationProperties(Twitter4jProperties.class)
public class Twitter4jAutoConfiguration {
@Autowired
private Twitter4jProperties properties;
Chapter 4: Creating Custom SpringBoot Starter 51
@Bean
@ConditionalOnMissingBean
public TwitterFactory twitterFactory(){
if (this.properties.getOauth().getConsumerKey() == null
|| this.properties.getOauth().getConsumerSecret() == null
|| this.properties.getOauth().getAccessToken() == null
|| this.properties.getOauth().getAccessTokenSecret() == null)
{
String msg = "Twitter4j properties not configured properly." +
" Please check twitter4j.* properties settings in confi\
guration file.";
log.error(msg);
throw new RuntimeException(msg);
}
@Bean
@ConditionalOnMissingBean
public Twitter twitter(TwitterFactory twitterFactory){
return twitterFactory.getInstance();
}
<parent>
<groupId>com.sivalabs</groupId>
<artifactId>spring-boot-starter-twitter4j</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.sivalabs</groupId>
<artifactId>twitter4j-spring-boot-autoconfigure</artifactId>
<version>${project.version}</version>
</dependency>
Chapter 4: Creating Custom SpringBoot Starter 53
<dependency>
<groupId>org.twitter4j</groupId>
<artifactId>twitter4j-core</artifactId>
</dependency>
</dependencies>
</project>
Note that in this maven module we are actually pulling in twitter4j-core dependency.
We dont need to add any code in this module, but optionally we can specify what are
the dependencies we are going to provide through this starter in src/main/resources/META-
INF/spring.provides file as follows:
provides: twitter4j-core
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.6.RELEASE</version>
Chapter 4: Creating Custom SpringBoot Starter 54
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.sivalabs</groupId>
<artifactId>twitter4j-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
package com.sivalabs.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringbootTwitter4jDemoApplication {
package com.sivalabs.demo;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import twitter4j.ResponseList;
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterException;
@Service
public class TweetService {
@Autowired
private Twitter twitter;
package com.sivalabs.demo;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import twitter4j.TwitterException;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(SpringbootTwitter4jDemoApplication.class)
public class SpringbootTwitter4jDemoApplicationTest {
@Autowired
private TweetService tweetService;
@Test
public void testGetTweets() throws TwitterException {
List<String> tweets = tweetService.getLatestTweets();
for (String tweet : tweets) {
System.err.println(tweet);
}
}
Now when you run this JUnit test you should be able to see the latest tweets on your console output.
Chapter 4: Creating Custom SpringBoot Starter 57
To learn more about creating custom AutoConfiguration classes or starters take a look at Creating
your own auto-configuration
4.5. Summary
In this chapter, we learned about how to create our own AutoConfiguration classes and our own
SpringBoot Starter. In next chapter, we will look into various SpringBoot features which we will be
using commonly in Spring based applications.
http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-developing-auto-configuration
Appendix A : Resources
You can find the useful information about SpringBoot at the following URLs:
http://spring.io/
http://projects.spring.io/spring-boot/
http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/
http://spring.io/guides
https://github.com/spring-projects/spring-boot
58