The labs on this site need JavaScript to run. The same content is written out below.
Fundamentals › Spring
What is a bean, and how does it differ from an object you just created?
A bean is an object that Spring creates and keeps. In code it is an ordinary class. If you write @Component above the class, then when Spring starts it scans the app package, finds that class, creates one object, and puts it in a place for keeping objects called the container. We do not use new. Where we need the object, we ask Spring for it with context.getBean(Greeter.class), and however many times we ask, Spring gives us the same one object it was keeping. In this lab you run the same code while removing @Component or creating the object with new Greeter() instead of getBean, and see how many objects Spring created, how many objects our code created with new, and whether a == b is true or false.
Checked against real execution · Ran 4 combinations with real component scanning on Spring Framework 7.0.9, measured the number of objects, and checked against the results
// Mark: Spring creates an object of this class and keeps it
@Component
public class Greeter {
public String hello() {
return "Hello";
}
}
public class Main {
public static void main(String[] args) {
// Start Spring. It scans the app package for @Component
ApplicationContext context =
new AnnotationConfigApplicationContext("app");
// Ask for the Greeter object that Spring is keeping
Greeter a = context.getBean(Greeter.class);
Greeter b = context.getBean(Greeter.class);
System.out.println(a.hello());
System.out.println(a == b);
}
}
These are the results of running Spring Framework 7.0.9 on JDK 21.0.12.1. Spring Boot was not used, and only AnnotationConfigApplicationContext("app") was used, as in the code on the screen. All 4 combinations were run as they are, by compiling a source with the same structure as the code on the screen (Greeter and Main in the package app) and starting a new Java process. Greeter was not registered by hand, and Spring was made to scan the app package and find @Component. What was checked is the text that the program printed (Hello and the value of a == b), the kind of exception when it stopped with an exception, the number of Greeter objects created by Spring, and the number of objects created by our code with new. The numbers of objects were measured, not guessed. Only in the source used for checking, a line that increases a number each time an object is created was added to the constructor of Greeter, and the count right after Spring started was recorded as the number created by Spring, and the count at the end minus that count was recorded as the number our code created with new. The count right after starting was already 1 (when @Component is present) before getBean was called, so Spring creates the object when Spring starts, not when getBean is called. Calling getBean twice did not increase the count and a == b was true, and in the combinations that use new, the number of Greeter beans in the container was the same at the end as right after starting, so objects created with new did not go into the container. When @Component was absent, the count right after starting was 0 and there were no registered names in the container (Spring's internal ones were excluded), and at the getBean line org.springframework.beans.factory.NoSuchBeanDefinitionException (the message says there is no bean of type app.Greeter) occurred, the process ended with an error code, and nothing was printed. When @Component was present, there was one registered name in the container, greeter, and that bean was a singleton. What the documentation specifies is the following sections of the Core part of the Spring Framework documentation. Introduction to the Spring IoC Container and Beans (a bean is an object that is created, assembled, and managed by the Spring IoC container, and an object that is not is just one of the many objects in the application), Classpath Scanning and Managed Components (@Component is a generic annotation for a component managed by Spring, and @Service, @Controller, and others are specializations of it; Spring finds annotated classes and registers bean definitions; and if no name is given, the class name with its first letter in lowercase is used), Bean Scopes (singleton is the default scope, and the container creates exactly one object for that bean definition and returns that object every time a request comes), and the API documentation of AnnotationConfigApplicationContext(String... basePackages) (it finds components in the given packages, registers bean definitions, and refreshes the context automatically). Unlike what the documentation specifies, that the object is created at startup, that a class without @Component is not created even if getBean is called, and the name of the exception are behaviors observed on this version. The code on the screen leaves out the package and import lines, and assumes that Greeter and Main are both in the app package. The line that closes the container was not used. Besides @Component, there are other ways to register a bean, such as a @Bean method, and @Service and @Controller, which belong to the @Component family, beans whose scope is not singleton, and dependency injection, which connects beans to each other, are not covered. They are covered in the in-depth lab "The Spring container and beans".
Previous lab: Libraries and dependencies · Next lab: Dependency injection
Struck-through text was removed from the first version of the code; highlighted text was added.