Spring BootJava 21Spring Framework深入淺出

Spring Boot 02: who creates beans? Injection and auto-configuration

··3 min read
Back to the Spring Boot learning path

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

java
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

MechanismRole in this labWhat it does not mean
StarterAdds related Maven dependenciesNot itself a running bean
Component scanFinds annotated application componentsDoes not scan every arbitrary package
@BeanRegisters an object through a configuration methodNot required for every application class
Auto-configurationApplies conditions based on libraries, configuration, existing beansDoes not infer business requirements
Ask whether it manages libraries or objects.

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.

bash
java -jar target/boot-learning-lab-1.0.0.jar --debug

Start 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

Sources