Let’s take a look at a list of important spring boot annotations and when to use them with an example.
What are annotations?
Annotations are a form of hints that a developer can give about their program to the compiler and runtime. Based on these hints, the compilers and runtimes can process these programs differently. That is exactly what happens with annotations in spring boot. Spring Boot uses relies on annotations extensively to define and process bean definitions. Some of the features we discuss here are from Spring Framework. But Spring Boot itself is an opinionated version of Spring.
Spring Boot annotation catagories
Based on the use case, Spring annotations fall in to one the following categories.
- Bean definition annotations (from Core Spring Framework)
- Configuration annotations
- Spring Component annotations
- Other modules Specific spring-boot annotations
1. Spring Core Annotations
These annotations are not part of spring boot but the spring framework itself. These annotations deal with defining beans. So, Lets look at each of these in details.
@Bean
You should use the @Bean on a method that returns a bean object. For example, you could define a bean as shown below.
@Bean
public MyService getMyService(){
MyDto dto = new MyDtoImpl();
MyService myService = new MyServiceImpl();
myService.setDto(dto);
return myService
}
Code language: Java (java)
@Autowired
The @Autowired
annotation lets you inject a bean wherever you want(most importantly factory methods like the one we seen above). For example, we needed a MyDto
for MyService
in our previous example. As we had to hardcode in that example, you can simplify it as shown here.
@Bean
public MyDto myDto() {
return new CustomDtoImpl();
}
@Bean
public MyService myServiceUsingAutowiring(@Autowired MyDto myDto) {
MyService myService = new MyServiceImpl(myDto);
return myService;
}
Code language: Java (java)
As you see here, @Autowired annotation makes sure spring boot loads an appropriate MyDto
bean. Note that, you would get an error if you haven’t defined a MyDto
bean. You could work around this by setting @Autowired(required=false)
.
@Bean
public MyService myServiceUsingAutowiringRequiredFalse(@Autowired(required = false) MyDto myDto) {
if(myDto==null){
myDto = new DefaultMyDtoImpl();
}
MyService myService = new MyServiceImpl(myDto);
return myService;
}
Code language: Java (java)
This approach provides you a default approach that you can override later.
You could also use the @Autowired annotation for arbitrary number of beans. This is done by setting the annotation at the method level. For instance, take a look at this snippet.
@Bean
@Autowired
public OrderService myServiceUsingAutowireMultiple(PaymentService paymentService,
StockService stockService,
EmailService emailService) {
//create and return order Service
}
Code language: Java (java)
In the above scenario, all three beans must be defined for the myServiceUsingAutowireMultiple
factory method to succeed.
@Required
Similar to setting required
flag in @Autowired
, you should use this annotation to mark a certain field or setter method as required. For instance, take a look at this snippet.
public class OrderService {
private PaymentService paymentService;
@Required
public void setMovieFinder(PaymentService paymentService) {
this.paymentService = paymentService;
}
//do stuff
}
Code language: Java (java)
2. Spring Boot Configuration annotations
Spring Boot favors java annotations over xml configurations. Even though both of them have pros and cons, the annotations help create complex configurations that work dynamically. So lets go thorough each of these with some examples.
@SpringBootApplication
The @SpringBootApplication
annotation is often used in the main class. This annotation is equivalent to using @Configuration
, @EnableAutoConfiguration
and @ComponentScan
together. This annotation is responsible for setting up which autoconfiguration to enable and where to look for spring bean components and configurations.
@SpringBootApplication
public class SpringHowApplication {
public static void main(String[] args) {
SpringApplication.run(SpringHowApplication.class, args);
}
}
Code language: Java (java)
@Configuration
This annotation is used together with the bean definition annotations. When the @ComponentScan finds a class that is annotated with @Configuration
, it will try to process all @Bean
and other spring related methods inside it.
@Configuration
public class BeanDefinitionExamples {
@Bean
public MyService myService() {
MyDto myDto = new MyDtoImpl();
MyService myService = new MyServiceImpl(myDto);
return myService;
}
//more beans
}
Code language: Java (java)
Configuration properties
This spring boot specific annotation helps bind properties file entries to a java bean. For example, take a look at these configs.
app.maxOrderPriceLimit=1000
app.payment.enabled=true
app.payment.types=card,cash
Code language: Java (java)
Let’s map these into a java bean.
@Configuration
@ConfigurationProperties("app")
public class AppConfig {
private int maxOrderPriceLimit = 0;
private PaymentConfig payment;
//getter setter
static class PaymentConfig {
List<String> types;
boolean enabled;
//getter setter
}
}
Code language: Java (java)
If setup correctly, Spring boot will create a AppConfig bean object with values mapped from properties. Subsequently, We can autowire them wherever we want.
@Value annotation
This annotation is similar to @Autowired
. Except this one is for accessing properties entries instead of beans.
@Component
public class LanguageService{
private final String defaultLang;
public LanguageService(@Value("${app.lang.default}") String lang) {
this.defaultLang= lang;
}
}
Code language: Java (java)
You could also use @Value
to access complex SpEL expressions.
there are other few spring boot annotations for configurations that we would not discuss here.
Spring Component annotations
While @Bean lets you create bean using factory methods, you could simply mark a class with one of the following component annotations. These annotations create a singleton bean of that specific class.
In a way these spring boot annotations provide context to what those beans represent in the system. They are,
- Component
- Controller
- Repository
- Service
@Component annotation
This is the basic version among those four. This annotation on a class makes a singleton bean of that said class. For example, the following creates a bean of type BookService with the name “bookService”.
@Component
public class BookService {
private Dto dto;
public BookService(Dto dto) {
this.dto = dto;
}
public List<String> getBookNames(){
return dto.getBookNames();
}
}
Code language: Java (java)
Once the component scan finds this class, it will try to use the constructor to create a BookService
object. As you see here, the constructor needs a Dto
bean. So spring boot will look for one that satisfies that requirement.
@Service Spring boot annotation
This annotation is similar to Component in everyway. The only reason to use a @Service
annotation instead of @Component
is for convention(domain driven design).
@Controller annotation
The @Controller
marks a class as a spring web MVC controller. This annotation is usually used along with web based spring applications. Apart from the MVC related features it brings, the rest of the behavior stands in line with @Component
.
@Controller(value = "bookController")
public class BookController {
public BookService bookService;
public BookController(BookService bookService) {
this.bookService = bookService;
}
@RequestMapping(method = RequestMethod.GET, path = "/books")
@ResponseBody
String<List> getNames() {
return bookService.getBookNames();
}
}
Code language: Java (java)
Once the spring MVC sees a controller class, it looks for all @RequestMapping
and configures them to handle requests. We will take a look at these in detail later.
There is also a restful variant of @Controller called @RestController
. There is also @GetMapping, @PostMapping and other mapping annotations available part of Spring MVC. They are more specialized versions of @RequestMapping annotations.
@RequestMapping
The request mapping annotation lets spring MVC know which controller class method to call. This annotation takes two parameters called path
and method
. This way we could map them based on path as well as HTTP methods like , GET, POST, PUT and DETELE.
@RequestMapping(method = RequestMethod.GET, path = "/books")
Code language: Java (java)
@ResponseBody
The response body is an optional annotation for controller methods. When supplied, this annotation will convert the method return value in to JSON response.
For example, the above code would return a JSON array of strings.
@Repository annotation in Spring Boot
The repository annotation is a bit different among all other stereotypes annotations. Even though this annotation is used extensively in JPA, this annotation came into picture as part of Domain Driven Design.
A common use case would be to annotate JPA repository interfaces. This way Spring-JPA module can provide JPQL support. For example, We could write a BookDto as shown here.
@Repository
public interface BookDto extends JpaRepository<Book, Integer> {
@Query("select b.name from Book b")
public List<String> getBookNames();
}
Code language: Java (java)
Even though we don’t need to annotate interfaces that extend, it is still a good convention. Also, apart from being a repository, all behaviours from @Component
is applicable for @Repository
annotation.
Spring boot Module-specific annotations
As spring boot comes with various modules like JPA, MVC, RabbitMQ, Scheduling, caching etc., all of these modules also provide their own annotations for us to use. We have seen some of the annotations from JPA and MVC. So let’s go through the remaining quickly.
Scheduling related annotations
The @Scheduled annotation helps make a method execute on a specific interval.
@Scheduled(fixedRate = 10000L)
public void executeEvery10Seconds(){
System.out.println("current time is "+ new Date());
}
Code language: Java (java)
This annotation takes one of fixedDelay
, fixedRate
or quartz compatible cron
expression.
@Scheduled(cron = "0 15,30,45 * ? * *")
public void scheduledCron(){
System.out.println("Runs every hour at minutes 15, 30 and 45");
}
Code language: Java (java)
Caching annotations
Caching annotations play important role in application performance. The cache abstraction in spring boot is powerful and you should take a look. Here are the important annotations from this module.
The @EnableCaching annotation enables support for caching by auto-configuring a cache manager. Usually this annotation goes on the spring boot’s main class.
@EnableCaching
@SpringBootApplication
public class SpringBootAnnotationsApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootAnnotationsApplication.class, args);
}
}
Code language: Java (java)
@Cacheable annotation marks a method’s return values to be cacheable. This way, when the first time the method was called with a specific parameter, the value is saved in the cache. If another request calls the same method with the same parameter, spring boot will return the value from cache instead of executing the method.
@Cacheable(value = "items", key = "#id")
public Item getItem(Integer id) {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Item item = itemRepository.findById(id).orElseThrow(RuntimeException::new);
logger.info("Loading data from DB {}", item);
return item;
}
Code language: Java (java)
As you can see, it takes a cache name and a key to store the result. This way when a new request comes with the same key, we could get the result from cache instead of running the method again.
The @CacheEvict annotation lets you clear a specific value from the cache. It could also be used to clear the entire cache if needed. This annotation exists because your cached results may be outdated and might need a refresh. For example, if you update an entity in DB, then you might want to clear the cached value as well.
@CacheEvict(value = "items", key = "#id")
public Item updateItem(Integer id, Item request) {
Item item = getItem(id);
item.setPrice(request.getPrice());
item.setProductName(request.getProductName());
return itemRepository.save(item);
}
Code language: Java (java)
AMQP/RabbitMQ annotations
The AMQP module provides certain annotations to deal with message queues of RabbitMQ. The important annotations are listed here.
The @EnableRabbit adds autoconfiguration for AMQP. This annotation is responsible for enabling RabbitAutoConfiguration
. Without this annotation, the remaining AMQP annotations won’t work.
@RabbitListener takes a queue name and executes the annotated method. For example, you could read messages from queues as shown here.
@RabbitListener(queues = "helloPojo")
public void getPojo(Notification message) {
logger.info("From Queue : {}", message);
}
Code language: Java (java)
There are also few annotations like @Exchange
, @queue
and @QueueBinding
which are used along with @RabbitListener.
Summary
We saw a hand-picked list of important annotations used in spring boot. These annotations solve the problem of defining spring beans, utilize them dynamically and configure them. You can find most of these annotations in the samples available in our Github repository.