Spring Boot 02: who creates beans? Injection and auto-configuration
TicketController calls service.find without constructing a TicketService. Java does not invent the object: Spring supplies the dependency when it creates the controller. Find this construction path before treating annotations as magic.
A bean is a container-managed object
public TicketController(TicketService service, LabProperties properties) {
this.service = service;
this.properties = properties;
}
public TicketService(TicketStore store, LabProperties properties) {
this.store = store;
this.properties = properties;
}These constructors come from the lab’s controller and service. They declare required collaborators and store them in final fields. Spring resolves the service’s own dependencies before supplying it to the controller; source-file order is not the construction algorithm. A single constructor here does not need @Autowired.
You can still construct ordinary objects with new. However, a manually created instance does not automatically receive Spring injection, lifecycle handling, or proxies just because its class has @Service. new Ticket is appropriate for a data value; manually constructing a service bypasses the transaction conditions used by this lab.
Four mechanisms that are easy to confuse
| Mechanism | Role in this lab | What it does not mean |
|---|---|---|
| Starter | Adds related Maven dependencies | Not itself a running bean |
| Component scan | Finds annotated application components | Does not scan every arbitrary package |
| @Bean | Registers an object through a configuration method | Not required for every application class |
| Auto-configuration | Applies conditions based on libraries, configuration, existing beans | Does not infer business requirements |
TicketStore is discovered by scanning. JdbcClient and DataSource are assembled when the relevant libraries and configuration satisfy their conditions. Some auto-configuration backs off when you define your own bean; inspect the specific conditions rather than assuming every default still applies, particularly with EAP-managed resources.
java -jar target/boot-learning-lab-1.0.0.jar --debugStart with --debug to inspect the condition evaluation report. Search for the data-source configuration and identify why conditions matched or failed. The report explains configuration decisions; it does not establish correct credentials, SQL behavior, or API compatibility.
Shared objects need appropriate state
A bean defaults to singleton scope within its container. A controller can handle concurrent requests, so request-specific users, inputs, or tickets do not belong in mutable instance fields. This lab stores stable collaborators and keeps ticket values local. Singleton scope neither means exactly one instance across the JVM nor guarantees thread safety.
Exercise: remove one required bean
In a disposable copy, temporarily remove @Repository from TicketStore and run mvn package. Expect a missing TicketStore during test-context startup, not an HTTP 404. Restore the annotation and rerun the tests after reading the cause; skipping tests does not repair the wiring.
Answer and extension: what if there are two candidates?
A missing required dependency prevents construction; ambiguous candidates can also fail when selection rules do not resolve them. First determine why two candidates exist, then express intent through a qualifier or explicit configuration. Do not add @Primary merely to silence the error. Name the object and collaborator involved before changing wiring.
Download the complete ticket API lab (ZIP)Next: 03: Configuration and profiles