What is a Spring Bean?
Introduction
Veggie lovers may feel a little warmth in their hearts at the mention of Spring beans. However, when we talk about Spring beans in programming we are speaking of a much different concept; this type of bean may not give us a kick of green, but it can certainly add a jolt to our software.
A highly coveted skill in programming is being able to write reusable code. In this article, we will explore Spring Beans: what they are, how they help facilitate reusability in software, and how they are used within the Spring framework.
- The Spring framework defines a Spring bean as an object managed by the Spring Inversion of Control (IoC) container.
The Spring IoC container’s management of beans includes several responsibilities. Perhaps the most significant of which include bean instantiation/assembly and the management of dependency injections. Let’s take a look at each of these key features to gain a greater understanding of beans and how the Spring framework abstracts the complexity away with simple, easy-to-use annotations.
Bean-stantiation
For this article, we assume an understanding that classes are templates from which objects are created. The process of creating an instance from a class is known as instantiation. In terms of reusability, we should also have the understanding that custom objects can be nested inside of other classes.
Normally, instantiating an object from a class requires the use of the new
keyword. Let’s take a look at how we would normally use nested objects and compare it to a similar process when using Spring beans.
Imagine we are designing a racing game. For each round of the race we need a race track and drivers. We could create a class for both as shown below.
public class RaceTrack {private String location;private int miles;private String trackType;}public class Driver {private String name;private String team;private int yearsExperience;}
Now let’s create a class that can be used for each round of the race.
public class RaceRound {private String startTime;private RaceTrack currentRaceTrack = new RaceTrack();private Driver currentDriver = new Driver();}
For each round of the race we would need to instantiate a RaceTrack
and a Driver
, so we would use the new
keyword to handle those instantiations. Any changes to those two classes would require additional changes in the RaceRound
class.
Now let’s take a look at how instantiating the nested objects would work with Spring beans. We would first mark our RaceTrack
and Driver
classes as Spring beans using the @Component
annotation:
@Componentpublic class RaceTrack {private String location;private int miles;private String trackType;}@Componentpublic class Driver {private String name;private String team;private int yearsExperience;}
Then we remove the actual instantiation code from RaceRound
, instead using the @Autowired
annotation:
public class RaceRound {private String startTime;@Autowiredprivate RaceTrack currentRaceTrack;@Autowiredprivate Driver currentDriver;}
Notice we are no longer using the new
keyword when creating instances of RaceTrack
and Driver
. So, how are we able to declare and use an instance without instantiating it?
We marked our dependent classes RaceTrack
and Driver
as Spring beans, which allows the IoC container to manage them, i.e. instantiate them and inject them into our RaceRound
class.
As an additional bonus, we didn’t have to edit the existing code in our RaceTrack
and Driver
classes to turn them into Spring beans. All we had to add was the @Component
annotation. There is an additional, older way to do this with XML configuration, but we’ll focus on the more modern annotations approach.
Note: @Component
and @Autowired
are just two of many annotations for working with Spring beans and the IoC container. When reading this article, focus on the general programming patterns rather than specific code.
Auto-beans loading…
The fully-automatic annotations approach is facilitated using three annotations:
@Configuration
, which notifies the framework that beans may be created via the annotated class.@ComponentScan
, which tells the framework to scan our code for components such as classes, controllers, services, etc.@EnableAutoConfiguration
, which tells the container to auto-create beans from the found components.
Together these three annotations tell the framework where to start looking, how to search our code, and automatically instantiate beans from the found components.
Using three separate annotations may seem hard to recall. However, remember when we said “the Spring framework abstracts the complexity away with simple, easy-to-use annotations”? This remains true as these three significant annotations have been wrapped up into one.
The @SpringBootApplication
annotation is a compilation of @Configuration
, @ComponentScan
, and @EnableAutoConfiguration
. When we apply the @SpringBootApplication
annotation to the class containing our main method, our application runs with all of this built-in functionality. Therefore, when our application starts up the container scans our code for components from which beans should be instantiated.
You can find this annotation provided in most default Spring projects:
@SpringBootApplicationpublic class RecipeApplication {public static void main(String[] args) {SpringApplication.run(RecipeApplication.class, args);}}
Now let’s take a look at what happens during the bean creation process.
Cooking with Beans
We are familiar with the notion of classes containing properties and methods. The Spring framework represents beans as a BeanDefinition
object. The BeanDefinition
object has several properties, but two are particularly interesting. There is a property named class
and there is a property named properties
.
When we define classes, we give them a particular name, such as RaceRound
. When the container instantiates a bean from this class it populates the class
property of that bean with the fully qualified name we have provided. So, if the fully qualified name of our class is com.package.RacingGame.RaceRound
, the class
property of the bean becomes com.package.RacingGame.RaceRound
. The class
property is Spring’s way of representing the bean’s underlying Java type so it knows what to instantiate.
The properties
property of the bean is populated from the properties of our class. If we have used a built-in type such as an int or a string, the container converts the property of our class into the same type of property for the bean. However, if we have used a custom type, such as RaceTrack
or Driver
, this is a dependency and the container now has to create a BeanDefinition
object for each of these types as well. Ultimately, the classes we create become part of a recipe for the container to use when creating beans.
When a class encapsulates other objects, the referenced objects become a dependency for the outer class. In other words, these other objects must be created so the outer class can use it. The container takes a look at our classes and, depending on the method you choose, instantiates beans from the referenced objects (RaceTrack
and Driver
) before it instantiates a bean from the outer classes (RaceRound
). Spring implements a way for the objects needed by another object to be provided as beans for others to reference. This process is known as dependency injection; Our classes no longer have to instantiate their own dependencies. Therefore, we can say the control of dependencies has been inverted back to the container, and this is why we call it an Inversion of Control (IoC) container.
Bean there, done that
In our previous examples, we declared our dependencies in RaceRound
with fields and annotated them with @Autowired
. In other Spring applications, you’ll often see dependencies injected via the constructor (which doesn’t require an annotation). In this example, the dependency is CoffeeRepository
:
public class CoffeeController {private final CoffeeRepository coffeeRepository;public CoffeeController(CoffeeRepository coffeeRepo) {this.coffeeRepository = coffeeRepo;}}
We include this example to show that there are many ways that the IoC container can use Spring beans in our applications. The important thing to focus on–rather than any one annotation– is the value of Spring beans, the IoC container, and annotations generally.
Finishing off the beans
In conclusion, Spring beans are objects managed by the IoC container. When we run our Spring application, the framework searches our code and creates beans from any components it has found. Part of the bean creation process involves ensuring any nested beans are available for use. Overall, Spring allows developers to encompass a significant amount of functionality with simple annotations and the IoC container’s management of beans is an invaluable resource. Hopefully, this article has provided you with a deeper understanding of Spring beans. Happy coding!
Author
The Codecademy Team, composed of experienced educators and tech experts, is dedicated to making tech skills accessible to all. We empower learners worldwide with expert-reviewed content that develops and enhances the technical skills needed to advance and succeed in their careers.
Meet the full team