What is a Spring Bean?

Learn about the fundamental components of a Spring application: Spring beans

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 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:

@Component
public class RaceTrack {
private String location;
private int miles;
private String trackType;
}
@Component
public 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;
@Autowired
private RaceTrack currentRaceTrack;
@Autowired
private 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:

@SpringBootApplication
public 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

Codecademy Team

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