Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Spring @Component versus @Bean: choose who constructs the dependency

Last updated: 1 Oct 20265 min read
tutorial
IntermediateBy AITrove Editorial

Spring registers a bean definition either by discovering a component in a scanned package or by calling a configuration method marked @Bean. Both paths produce container-managed objects; they differ in who controls construction.

Keep the scan boundary visible

A Boot application scans from its application package downward by default. Moving a service outside that tree can make constructor injection fail at startup. Annotating more classes will not repair an excluded package. Place the application class above its features or configure an intentional scan boundary.

Use @Component or a role-specific stereotype for a class your team owns. Use @Bean when construction needs an external library constructor, a configured timeout, or an adapter selected at startup. A @Bean factory method can receive other beans as parameters; that keeps the dependency list explicit.

Java
package in.aitrove.receipts;

import java.time.Clock;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;

@SpringBootApplication
public class ReceiptApplication {
    @Bean
    Clock receiptClock() {
        return Clock.systemUTC();
    }
}

@Service
class ReceiptExpiryPolicy {
    private final Clock receiptClock;

    ReceiptExpiryPolicy(Clock receiptClock) {
        this.receiptClock = receiptClock;
    }

    boolean expired(java.time.Instant deadline) {
        return !deadline.isAfter(receiptClock.instant());
    }
}

Know what the container actually owns

Calling new ReceiptExpiryPolicy(...) yourself creates an ordinary object. Spring does not inject or apply proxy advice to it. Conversely, calling a bean through the container does not make the bean thread-safe. A singleton policy should hold dependencies, not mutable request state.

The factory method above returns a process-wide UTC clock. Tests can replace that bean with a fixed clock; they should not sleep until a deadline. Bean creation itself is normally startup work, while each expired check is constant time and creates no collection.

Common Mistakes

  • Assuming a stereotype is scanned when its package is outside the application boundary.
  • Registering both a scanned component and a @Bean of the same service type without deciding which injection should win.
  • Putting a changing request value in a singleton field.
  • Expecting advice or injection on an object constructed with new.

Read next

Constructor injection, ambiguous beans, and Java Clock tests.

spring
spring-boot
component-scan-vs-bean
Storage details