The First Spring Boot Application
Create your first Spring Boot application from scratch, understand the project structure, and explore auto-configuration
To understand Spring Boot, let's write our first Spring Boot application and see how it differs from the Spring applications we've written before.
We create a springboot-hello project and set up a standard Maven directory structure.
Project Directory Structure
springboot-hello
├── pom.xml
├── src
│ └── main
│ ├── java
│ └── resources
│ ├── application.yml
│ ├── logback-spring.xml
│ ├── static
│ └── templates
└── targetWithin src/main/resources directory, note the following important files:
application.yml - Configuration File
This is the default configuration file for Spring Boot. It uses YAML format instead of .properties format, and the filename must be application.yml.
Using .properties format:
# application.propertiesspring.application.name=${APP_NAME:unnamed}spring.datasource.url=jdbc:hsqldb:file:testdbspring.datasource.username=saspring.datasource.password=spring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriverspring.datasource.hikari.auto-commit=falsespring.datasource.hikari.connection-timeout=3000spring.datasource.hikari.validation-timeout=3000spring.datasource.hikari.max-lifetime=60000spring.datasource.hikari.maximum-pool-size=20spring.datasource.hikari.minimum-idle=1Using YAML format:
# application.ymlspring:application:name: ${APP_NAME:unnamed}datasource:url: jdbc:hsqldb:file:testdb
username: sa
password:driver-class-name: org.hsqldb.jdbc.JDBCDriver
hikari:auto-commit:falseconnection-timeout:3000validation-timeout:3000max-lifetime:60000maximum-pool-size:20minimum-idle:1YAML Advantages
YAML is a hierarchical format that removes many repeated prefixes and offers greater readability.
Using Environment Variables
In configuration files, we often use environment variables with default values:
app:db:host: ${DB_HOST:localhost}user: ${DB_USER:root}password: ${DB_PASSWORD:password}The syntax ${DB_HOST:localhost} means: first check the environment variable DB_HOST. If defined, use its value; otherwise, use localhost.
Running with environment variables:
$ DB_HOST=10.0.1.123 DB_USER=prod DB_PASSWORD=xxxx java-jar xxx.jarlogback-spring.xml - Logging Configuration
This is the Spring Boot logback configuration file. A standard configuration looks like this:
<?xml version="1.0" encoding="UTF-8"?><configuration><includeresource="org/springframework/boot/logging/logback/defaults.xml"/><appendername="CONSOLE"class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>${CONSOLE_LOG_PATTERN}</pattern><charset>utf8</charset></encoder></appender><appendername="APP_LOG"class="ch.qos.logback.core.rolling.RollingFileAppender"><encoder><pattern>${FILE_LOG_PATTERN}</pattern><charset>utf8</charset></encoder><file>app.log</file><rollingPolicyclass="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"><maxIndex>1</maxIndex><fileNamePattern>app.log.%i</fileNamePattern></rollingPolicy><triggeringPolicyclass="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"><MaxFileSize>1MB</MaxFileSize></triggeringPolicy></appender><rootlevel="INFO"><appender-refref="CONSOLE"/><appender-refref="APP_LOG"/></root></configuration>Note: The static and templates directories are placed directly in src/main/resources (not src/main/webapp) because a dedicated webapp directory is no longer needed in Spring Boot.
Source Code Directory Structure
src/main/java
└── com
└── itranswarp
└── learnjava
├── Application.java
├── entity
│ └── User.java
├── service
│ └── UserService.java
└── web
└── UserController.javaImportant!
Spring Boot requires that the startup class containing main() method must be placed in the root package. Sub-packages like entity, service, web should be under the root package.
Application.java - The Main Class
@SpringBootApplicationpublicclassApplication{publicstaticvoidmain(String[] args)throwsException{SpringApplication.run(Application.class, args);}}Starting a Spring Boot application requires only one line of code and one annotation @SpringBootApplication, which actually includes:
@SpringBootConfiguration@Configuration@EnableAutoConfiguration@AutoConfigurationPackage@ComponentScanThis annotation is equivalent to enabling automatic configuration and automatic scanning.
pom.xml - Maven Configuration
<project...><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.0.0</version></parent><modelVersion>4.0.0</modelVersion><groupId>com.itranswarp.learnjava</groupId><artifactId>springboot-hello</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><java.version>17</java.version><pebble.version>3.2.0</pebble.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-jdbc</artifactId></dependency><!-- Pebble View Template --><dependency><groupId>io.pebbletemplates</groupId><artifactId>pebble-spring-boot-starter</artifactId><version>${pebble.version}</version></dependency><!-- JDBC Driver --><dependency><groupId>org.hsqldb</groupId><artifactId>hsqldb</artifactId></dependency></dependencies></project>Best Practice
Using Spring Boot, spring-boot-starter-parent inheritance is strongly recommended because it allows you to incorporate Spring Boot's built-in configurations. Version numbers don't need to be specified for Spring Boot managed dependencies.
Adding WebMvcConfigurer Bean
Add Pebble configuration to application.yml:
pebble:# Default is ".peb", change to "":suffix:# Disable template caching during development:cache:falseModify Application to add WebMvcConfigurer Bean:
@SpringBootApplicationpublicclassApplication{...@BeanWebMvcConfigurercreateWebMvcConfigurer(@AutowiredHandlerInterceptor[] interceptors){returnnewWebMvcConfigurer(){@OverridepublicvoidaddResourceHandlers(ResourceHandlerRegistry registry){// Map path `/static/` to classpath:
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");}};}}Running the Application
Run Application and observe the Spring Boot startup logs:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.0.0)
2022-11-25T10:49:31.100+08:00 INFO 13105 --- [main] c.i.learnjava.Application : Starting Application...
2022-11-25T10:49:32.404+08:00 INFO 13105 --- [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2022-11-25T10:49:32.423+08:00 INFO 13105 --- [main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2022-11-25T10:49:32.669+08:00 INFO 13105 --- [main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2022-11-25T10:49:32.998+08:00 INFO 13105 --- [main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection
2022-11-25T10:49:33.619+08:00 INFO 13105 --- [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080
2022-11-25T10:49:33.637+08:00 INFO 13105 --- [main] c.i.learnjava.Application : Started Application in 3.151 secondsSuccess!
When you see Started Application in xxx seconds, your Spring Boot application has started successfully. Access it at localhost:8080.
Understanding AutoConfiguration
Where were the data source, declarative transaction, and JdbcTemplate created? These automatically created beans are a feature of Spring Boot: AutoConfiguration.
When importing spring-boot-starter-jdbc:
- •
DataSourceAutoConfiguration- Creates DataSource from application.yml - •
DataSourceTransactionManagerAutoConfiguration- Creates JDBC transaction manager - •
JdbcTemplateAutoConfiguration- Creates JdbcTemplate
When importing spring-boot-starter-web:
- •
ServletWebServerFactoryAutoConfiguration- Creates embedded Tomcat - •
DispatcherServletAutoConfiguration- Creates DispatcherServlet - •
HttpEncodingAutoConfiguration- Creates CharacterEncodingFilter - •
WebMvcAutoConfiguration- Creates MVC-related beans
How Conditional Configuration Works
Spring Boot uses Spring's Conditional feature for auto-configuration. Here's how JdbcTemplateAutoConfiguration works:
@Configuration(proxyBeanMethods =false)@ConditionalOnClass({DataSource.class,JdbcTemplate.class})@ConditionalOnSingleCandidate(DataSource.class)@AutoConfigureAfter(DataSourceAutoConfiguration.class)@EnableConfigurationProperties(JdbcProperties.class)@Import({JdbcTemplateConfiguration.class,NamedParameterJdbcTemplateConfiguration.class})publicclassJdbcTemplateAutoConfiguration{}The actual creation is done by JdbcTemplateConfiguration:
@Configuration(proxyBeanMethods =false)@ConditionalOnMissingBean(JdbcOperations.class)classJdbcTemplateConfiguration{@Bean@PrimaryJdbcTemplatejdbcTemplate(DataSource dataSource,JdbcProperties properties){JdbcTemplate jdbcTemplate =newJdbcTemplate(dataSource);JdbcProperties.Template template = properties.getTemplate();
jdbcTemplate.setFetchSize(template.getFetchSize());
jdbcTemplate.setMaxRows(template.getMaxRows());if(template.getQueryTimeout()!=null){
jdbcTemplate.setQueryTimeout((int) template.getQueryTimeout().getSeconds());}return jdbcTemplate;}}Key Insight
If you create your own JdbcTemplate bean, Spring Boot will not create a duplicate one due to @ConditionalOnMissingBean.
Summary
Spring Boot is a suite of ready-to-use components based on Spring that allows us to quickly build a complete application with minimal configuration and code.
Spring Boot has a very powerful AutoConfiguration feature, which is achieved through automatic scanning and conditional configuration.
The startup class with @SpringBootApplication must be in the root package for component scanning to work correctly.