Spring Boot concepts in Java
IoC container, beans, auto-configuration, REST controllers.
new for it. Who did?Inversion of control
Normally your classes create their dependencies with new. With IoC, it's the opposite: Spring's container creates your objects (beans) and injects their dependencies. Classes stay loosely coupled and easy to test.
How beans are found
Classes marked **@Component, @Service or @RestController are found by component scanning. @Bean** methods inside a @Configuration class register objects you build yourself. **@SpringBootApplication** = configuration + auto-configuration + component scan.
Giving Checkout its client
@Service
class Checkout {
@Autowired
private PaymentClient client;
}Hidden, mutable dependency; hard to build in a unit test.
@Service
class Checkout {
private final PaymentClient client;
Checkout(PaymentClient c) {
client = c;
}
}Explicit and immutable; a test can call new Checkout(fake).
Auto-configuration
Spring Boot's auto-configuration creates sensible beans conditionally, based on the classpath and properties: add the JPA starter, a PostgreSQL driver and a URL, and a DataSource appears. Each piece is guarded by conditions like *class present* and *no bean of this type yet*.
Your own DataSource
You define your own DataSource bean. What happens to the one Boot would have created?
Think about it, then reveal the answer
Boot's auto-configured DataSource backs off, and yours is used. Auto-configuration only fills the gaps you leave.
State in a singleton
Beans are singletons by default: one shared instance per application context. All concurrent requests share its fields, so per-request mutable state like this gets mixed up between users.
@Service
class Cart {
private Order current; // shared by
// every request!
}REST in a few lines
A **@RestController** method's return value becomes the response body, typically JSON. Thanks to constructor injection, the same controller is easy to unit test: build it with a fake dependency, no Spring needed.
Key takeaways
- Prefer constructor injection with final fields
- Beans are singletons by default
- Auto-configuration is conditional and backs off
- @RestController return values become the response body (e.g. JSON)
Spring Boot's auto-configuration is ordinary configuration code guarded by conditions such as @ConditionalOnClass and @ConditionalOnMissingBean.
Practice questions
You add the JPA starter and a PostgreSQL driver and set the database URL. A DataSource bean appears though you never wrote one. Why?
- Every Spring app ships an in-memory DataSource
- Spring generates it from your SQL files
- Auto-configuration creates beans conditionally, based on the classpath and properties
- The JDBC driver registers itself as a Spring bean
Check your answer
Auto-configuration creates beans conditionally, based on the classpath and properties. Auto-configuration classes are guarded by conditions like 'class present on the classpath' and 'no bean of this type defined yet'.
What's the recommended way to give Checkout its PaymentClient?
@Service
class Checkout {
@Autowired
private PaymentClient client;
}- Make the field static so it's shared
- Call new PaymentClient() inside each method
- Look it up with context.getBean() on every call
- Constructor injection into a final field
Check your answer
Constructor injection into a final field. Constructor injection makes the dependency explicit and immutable, and lets you build the class in a unit test without Spring.