Spring Boot is famously easy to start a project with. You add a starter, you write a controller, you run the app, and somehow the database is talking to your service which is talking to your gateway. There's a lot happening behind the scenes — and almost all of it lives in the bean container.
This raises a fun question: how many beans does your project actually have right now?
The number is bigger than you'd expect. Even a small Spring Boot app pulls in hundreds of beans, most of which are auto-configured for you. Let's look at three ways to count them.
Spring vs. Spring Boot, quickly
Worth setting straight before we get into counting. Spring is the underlying framework; you pick the pieces you need and wire them up. Spring Boot sits on top and does the wiring for you, opting you into a set of sensible defaults via auto-configuration. That's why a brand-new Spring Boot project already has hundreds of beans before you've written a single class.
Approach 1: the Actuator /beans endpoint
Spring Boot Actuator exposes runtime information about your app through HTTP endpoints. One of them is /actuator/beans, which dumps every bean the container knows about.
Step 1. Add the dependency:
pom.xml1<dependency>
2 <groupId>org.springframework.boot</groupId>
3 <artifactId>spring-boot-starter-actuator</artifactId>
4</dependency>
Step 2. Expose the endpoint. By default Actuator only exposes /health, so you have to opt in:
management.endpoints.web.exposure.include=beans
Step 3. Start the app and call it:
1$ curl http://localhost:8080/actuator/beans
The response is a JSON document grouped by ApplicationContext. Each bean entry tells you its scope, its class, and which other beans it depends on:
1{
2 "contexts": {
3 "application": {
4 "beans": {
5 "dataSource": {
6 "aliases": [],
7 "scope": "singleton",
8 "type": "com.zaxxer.hikari.HikariDataSource",
9 "resource": "...",
10 "dependencies": []
11 },
12 "userController": {
13 "aliases": [],
14 "scope": "singleton",
15 "type": "com.example.web.UserController",
16 "dependencies": ["userService"]
17 }
18 }
19 }
20 }
21}
Counting the entries gives you the total. With jq:
1$ curl -s http://localhost:8080/actuator/beans | jq '.contexts.application.beans | length'
2312
Approach 2: ApplicationContext.getBeanDefinitionCount()
If you don't want a whole HTTP endpoint just to count beans, the ApplicationContext itself can tell you. Inject it anywhere, ask for getBeanDefinitionCount(), and you're done.
src/main/java/com/example/service/BeanCounterService.java 1@Service
2public class BeanCounterService {
3
4 private final ApplicationContext context;
5
6 public BeanCounterService(ApplicationContext context) {
7 this.context = context;
8 }
9
10 public int countBeans() {
11 return context.getBeanDefinitionCount();
12 }
13
14 public String[] beanNames() {
15 return context.getBeanDefinitionNames();
16 }
17}
Now you can expose it via a controller, log it, or call it from anywhere else in the app.
1@RestController
2public class DebugController {
3
4 private final BeanCounterService counter;
5
6 public DebugController(BeanCounterService counter) {
7 this.counter = counter;
8 }
9
10 @GetMapping("/debug/beans/count")
11 public Map<String, Integer> count() {
12 return Map.of("count", counter.countBeans());
13 }
14}
Approach 3: print on startup with CommandLineRunner
For a quick "how big is this app" check, CommandLineRunner is the lightest approach. The runner executes once, right after the context is fully built:
src/main/java/com/example/Application.java 1@SpringBootApplication
2public class Application {
3
4 public static void main(String[] args) {
5 SpringApplication.run(Application.class, args);
6 }
7
8 @Bean
9 public CommandLineRunner listBeans(ApplicationContext ctx) {
10 return args -> {
11 String[] names = ctx.getBeanDefinitionNames();
12 System.out.println("Total beans: " + names.length);
13
14 Arrays.stream(names)
15 .sorted()
16 .forEach(System.out::println);
17 };
18 }
19}
Run the app and you'll see something like:
Total beans: 312
applicationAvailability
applicationTaskExecutor
characterEncodingFilter
dataSource
...
Which one should you reach for?
It depends on what you're doing:
- Actively debugging wiring issues? The Actuator endpoint gives you the most context — names, types, dependencies — all at once.
- Building a real feature (like exposing diagnostics)? The
ApplicationContextAPI is the clean abstraction. Wrap it in a service and inject it where you need it. - One-off curiosity?
CommandLineRunneris the fastest. Three lines and you have your number on startup.
What you'll see
A fresh spring-boot-starter-web project clocks in around 160–200 beans before you've written anything. Add spring-boot-starter-data-jpa, and you're closer to 280. Add Security and Actuator, and you'll cross 350.
Most of those beans are auto-configurations — small classes that Spring Boot registers conditionally based on what's on your classpath. They're what makes Spring Boot feel like magic, and they're the reason the bean count is so much higher than what you'd guess from looking at your own code.
Wrap-up
The number of beans in your app isn't usually a metric you care about day-to-day. But the ability to ask — and the techniques to answer it — comes in handy whenever something isn't wiring the way you'd expect. Pick whichever of the three approaches fits the moment, and the bean container goes from feeling like a black box to a thing you can actually inspect.
