This is the first post in a series of posts to cover different aspects of Spring Boot. Please note that the entire post isn’t necessarily only written in English.
In this post, I am going to cover the basic concepts, and related files in a simple Spring Boot project, so let’s get started.
Concepts
Comparison
Old times:
The most common types of applications developed were browser-based web applications, backed by relational databases.
Nowadays:
Microservices destined for the cloud that persist data in a variety of databases
New interest in reactive programming, with non-blocking operations
Spring: ( Container + DI + Web MVC )
Offers a container: the Spring application context — creates & manages application components (= beans)
Components are wired together inside the Spring application context (beans wired in container)
Dependency Injection (DI):
A DI application relies on a separate entity (container) to create & manage all beans, and inject those into the beans that need them.
Done through: constructor argument, property accessor methods.
A DI container wires together independent components into a complete application at runtime.
Dependency injection means giving an object its instance variables. The fact that we can statically bind interfaces into the object’s method that instantiates it, serves a purpose for better lookup and stronger support for “programming to an interface“. Dynamic language is nothing but injecting dependencies runtime as the object knows nothing about the caller.
In a non-dependency-injection framework, the application is decomposed into classes where each class often has explicit linkages to other classes in the application. The linkages are the invocation of a class constructor directly in the code.
Spring is based on the concept of dependency injection.
A dependency injection framework externalize the relationship between objects within the application through convention & annotations, rather than those objects having hard-coded knowledge about each other.
Components = Beans in Spring application context:
- Declared explicitly with Xml / Java
- Discovered by component scanning
- Configured by Spring Boot autoconfig
Spring Web MVC:
- Web framework
- Annotation-based (e.g. request-handling methods with
@RequestMapping
,@GetMapping
, return template view name) - Supports Java Bean Validation API & Hibernate Validator
Spring Boot: ( Autoconfig + Starter dependencies + Runtime insights )
Start Spring Boot: log entry saying Tomcat started
- Spring Boot applications bring everything they need within them
- You never deploy your application to Tomcat, because Tomcat is part of your application
With starter-web
& Thymeleaf
, when starting the app, Spring Boot autoconfig detects those libraries and automatically:
- Config the beans in the Spring application context to enable Spring MVC
- Config embedded Tomcat server in the Spring application context
- Config a view resolver for Spring MVC view rendering with Thymeleaf
Additional features:
- Spring Boot CLI: command-line interface, alternative programming model based on Groovy scripts
- Actuator: provides runtime insight. (e.g. metrics, health, thread dump info)
- Additional testing support
- Flexible specification of env properties
Config (3 Ways)
Configure the Spring application context to wire beans:
XML file: describe components & their relation to other components
1 | <!-- Declares 2 beans: oneService & twoService --> |
Java-based config:
Greater type safety, more refactorable
1 | // @: indicates config class, provide beans to Spring application context |
Auto config:
Component scanning: auto discover components from application classpath, then create them as beans.
Autowiring: auto inject components along with the depended beans.
Spring Boot: Extension of the Spring framework. Improvement in autoconfig (No need Xml / Java config files).
Spring Boot can make guesses of what components need to be configured and wired together,
based on entries in the classpath, environment vars.
Pom File
mvnw
& mvnw.cmd
: Maven wrapper scripts
In pom.xml
: Use JAR packaging, instead of WAR. (Jar is better for the cloud)
War: Good for deploying to traditional Java app server (Tomcat), not good for most cloud platforms
- War deploy: war packaging + web initializer class (
web.xml
)
Parent pom:
spring-boot-starter-parent
- Provides dependency management for several libs frequently used in Spring projects.
Starter dependencies: they don’t have any library code, but pull from other libraries transitively
Web starter: includes embedded Tomcat
- Smaller build file, easy to manage
- Think of dependencies in terms of capabilities, but not library names
- Stop worrying about library versions & conflicts
Maven Plugin:
- Provides a Maven goal for you to run with Maven
- All dependencies are included within the executable JAR file, and are available on the runtime path
- Produces a manifest file in the JAR file: denotes the bootstrap class (
main.java
) as the main class for the executable JAR
- War deploy: war packaging + web initializer class (
Main Class
The bootstrapped main class:
1 |
|
The annotation @SpringBootApplication
: A composite annotation that combines 3 other annotations
@SpringBootConfiguration
: This is a config class (Specialized form of@Configuration
)@EnableAutoConfiguration
: enable autoconfig (config any components that it thinks you need)@ComponentScan
:- Let you declare other classes with annotations like
@Controller
,@Service
- Have Spring auto discover classes and register them as components int he Spring application context
- Let you declare other classes with annotations like
Main Test Class
Baseline test class:
1 | import org.junit.Test; |
此 baseline 测试的作用: check if the Spring application context can be loaded successfully.
@RunWith
: a JUnit annotation, provide a test runner that guides JUnit in running tests
- 相当于: applying a plugin to JUnit to provide custom testing behavior
- 上面例子中: the imported
SpringRunner
is a Spring-provided test runner (test the creation of a Spring application context) SpringRunner
=SpringJUnit4ClassRunner
- Introduced in Spring 4.3, to remove association with a specific JUnit version
Web Requests
Spring’s web framework: Spring MVC
Central concept of Spring MVC: controller —— A class that handles HTTP requests and response
- e.g. respond by optionally populating model data, then passing the request to a View to produce HTML
A sample controller:
1 | import org.springframework.stereotype.Controller; |
@Controller
: Primary purpose is to identify this class as a component (for component scanning)
- You could annotate
HomeController
as@Service
,@Repositoy
, and it still works the same (亲测,确实如此!)
Controller Test:
1 |
|
@WebMvcTest
: Arranges the test to run in Spring MVC application context
- 上面例子中: arranges to register
HomeController
in Spring MVC, so you can throw requests likeGET
DevTools
About dev tools:
- Auto application restart when code changes
- Auto browser refresh when template changes & Auto disable template cache
- Builtin H2 console for H2 database
- When deploying in a production environment, it will be self-disabled
With dev tools, the application is loaded into 2 separate class loaders in JVM.
- One is loaded with files under
/src/main
(may change frequently) - Other is loaded with dependency libraries (change less often)
Cons: dependency changes won’t be available in auto restarts
- Because the class loader containing dependency libraries isn’t automatically reloaded