Beans and the container
In a plain Java program you create objects yourself with new. In Spring this job is done by the container (also called the application context). At startup it finds your classes, creates one object of each and keeps them. An object managed by the container is called a bean.
How to mark a class
The container creates beans from classes with special annotations:
| Annotation | What for |
|---|---|
@Component | Any helper class |
@Service | A class with application logic |
@Repository | A class that works with data |
@Controller, @RestController | HTTP request handlers |
@Configuration | A class with settings and @Bean methods |
Technically all of them are kinds of @Component. The different names help reading: the annotation tells you the role of the class at a glance.
The first service
// src/main/java/com/example/blog/PostService.java
package com.example.blog;
import java.util.List;
import org.springframework.stereotype.Service;
@Service
public class PostService {
public List<String> titles() {
return List.of("Hello, Spring", "Why records");
}
}Thanks to @Service the container creates one PostService object at startup. You never need to call new PostService().
How to get a bean
Another bean receives the service through its constructor — Spring passes the ready object itself:
// src/main/java/com/example/blog/TitleController.java
package com.example.blog;
import java.util.List;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TitleController {
private final PostService postService;
public TitleController(PostService postService) {
this.postService = postService;
}
@GetMapping("/api/titles")
public List<String> titles() {
return postService.titles();
}
}The request curl http://localhost:8080/api/titles returns ["Hello, Spring","Why records"]. How exactly Spring picks constructor arguments is the topic of the next lesson.
Where Spring looks for classes
The search (component scanning) starts from the package of the class with @SpringBootApplication, that is com.example.blog, and covers all its subpackages. A class in com.example.blog.posts is found, one in com.example.other is not.
A bean from someone else's class
You cannot put an annotation on a library class. For such cases you write a @Bean method in a configuration class:
// src/main/java/com/example/blog/AppConfig.java
package com.example.blog;
import java.time.Clock;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public Clock clock() {
return Clock.systemUTC();
}
}Spring calls clock() once and keeps the result as a bean of type Clock named clock. Now any class can ask for a Clock in its constructor — handy for setting the creation date of a post.
Common mistake
If you forget the @Service annotation or put the class outside the com.example.blog package, the application does not start:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.example.blog.PostController required a bean of type 'com.example.blog.PostService' that could not be found.Spring is saying: the controller needs a PostService, but there is no such bean. Check the annotation and the package of the class.