Tuesday, November 15, 2022

Spring Boot - Annotation Reference - Part 01/a

In 2018, I was introduced to the topic of Microservices and Spring Boot via a formal training. This was during my brief stint as a Senior Architect in Manila, Philippines. Though I had worked on a 'similar architecture' way back in 2007-'08 while working as a Software Engineer at Symantec - I found the idea of the Uber JAR really exciting. Also, since it will now be enforced via the most popular framework brings in more possibilities. This includes building 'executable applications' for windows much easier!  



Anyways, The topic of our discussion is Spring Boot Annotations. Recently, In August 2022 while training a team of 10 - I realized that though even though I know most of the Spring Boot Annotations, I may not be aware of all of them. So, I decided to write this article. I hope it helps the readers to have a quick glance either during their daily work or as a general reference. Since I have been working on Spring Boot, Cloud, Spring Security, Spring Data since the last 4 years, I will later write a [Part-02] of this article covering the other annotations as well. It will cover annotations of Spring Security, Spring Data and Spring Cloud.

Herein, I will try to cover the annotations that you may most frequently see in daily development. Some of them you may know vaguely or just seen them in code but not understood completely. This article help you refresh what you already know and also to know more about the ones you had just come across.

GitHub Repository

[Spring Boot]
 
@SpringBootApplication
Well, this might be surprising. @SpringBootApplication is actually a combination of three features or annotations. In other words, it has the effect of 3 annotations together : @EnableAutoConfiguration, @ComponentScan, @Configuration. 
 
The main class of your Spring Boot Application should be annotated with this annotation, which has a main method.
 package xyz.sumithpuri.spring.boot.annotation;  
   
 import org.springframework.boot.SpringApplication;  
 import org.springframework.boot.autoconfigure.SpringBootApplication;  
 import org.springframework.context.annotation.Bean;  
   
 import xyz.sumithpuri.spring.boot.annotation.service.SBASampleImpl;  
 import xyz.sumithpuri.spring.boot.annotation.service.SBASampleInterface;  
   
   
 @SpringBootApplication  
 public class SpringBootAnnotationApplication {  
   
      public static void main(String[] args) {  
           SpringApplication.run(SpringBootAnnotationApplication.class, args);  
      }  
        
      @Bean  
      public SBASampleInterface getSBAService() {  
             
           return new SBASampleImpl();  
      }  
 }  
   

@EnableAutoConfiguration 
So, Spring allows the automatic configuration of the application, by creating and registering the spring beans in the classpath. The @EnableAutoConfiguration allows to define the base search package. By default, the base package for searching of beans will be the same package as of the class that declares this annotation.

Usually, you will place this annotation on your main class. If you use @SpringBootApplication, you may not need this annotation.
 package xyz.sumithpuri.spring.boot.annotation;  
   
 import org.springframework.boot.SpringApplication;  
 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;  
 import org.springframework.context.annotation.Bean;  
 import org.springframework.context.annotation.ComponentScan;  
 import org.springframework.context.annotation.Configuration;  
   
 import xyz.sumithpuri.spring.boot.annotation.service.SBASampleImpl;  
 import xyz.sumithpuri.spring.boot.annotation.service.SBASampleInterface;  
   
   
 //@SpringBootApplication  
 @EnableAutoConfiguration  
 @Configuration  
 @ComponentScan(basePackages = "xyz.sumithpuri.spring.boot.annotation")  
 public class SpringBootAnnotationApplication {  
   
      public static void main(String[] args) {  
           SpringApplication.run(SpringBootAnnotationApplication.class, args);  
      }  
        
      @Bean  
      public SBASampleInterface getSBAService() {  
             
           return new SBASampleImpl();  
      }  
 }  
   

@SpringBootTest
This one is straightforward, @SpringBootTest is used to create an application context object that supports testing.
 
You must annotate your Test Class file with this annotation
 package xyz.sumithpuri.spring.boot.annotation;  
   
 import org.junit.jupiter.api.Test;  
 import org.junit.runner.RunWith;  
 import org.springframework.boot.test.context.SpringBootTest;  
 import org.springframework.test.context.junit4.SpringRunner;  
   
 @RunWith(SpringRunner.class)  
 @SpringBootTest  
 class SpringBootAnnotationApplicationTests {  
   
      @Test  
      void contextLoads() {  
      }  
 }  
   

@SpringBootConfiguration
Even though I have not used it much in my applications, from what I could gather I have found it is already part of the @SpringBootApplication. The only difference that exists between @Configuration and @SpringBootConfiguration is that latter allows to automatically locate the configuration. This will be useful for unit and integration tests.


@ConditionalOnClass
Will match only when the specified classes are in the classpath.
 package xyz.sumithpuri.spring.boot.annotation.configuration;  
   
 import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;  
 import org.springframework.context.annotation.Bean;  
 import org.springframework.context.annotation.Configuration;  
   
 import xyz.sumithpuri.spring.boot.annotation.service.SBASampleImpl;  
 import xyz.sumithpuri.spring.boot.annotation.service.SBASampleInterface;  
   
 /**  
  * @author sumith.puri  
  *  
  */  
 @Configuration  
 @ConditionalOnClass(SBASampleImpl.class)  
 public class SBASampleConfiguration {  
        
      @Bean  
      public SBASampleInterface getSBAService() {  
             
           return new SBASampleImpl();  
      }  
 }  
   

With Spring DevTools Enabled, you will see one such log on the console that are the debug statements showing the matches or evaluations against the conditions.


@ConditionalOnProperty
Will match only when the specified environment property is present and it has a specific value.
 package xyz.sumithpuri.spring.boot.annotation.configuration;  
   
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;  
 import org.springframework.context.annotation.Bean;  
 import org.springframework.context.annotation.Configuration;  
   
 import xyz.sumithpuri.spring.boot.annotation.service.SBASampleImpl;  
 import xyz.sumithpuri.spring.boot.annotation.service.SBASampleInterface;  
   
 /**  
  * @author sumith.puri  
  *  
  */  
 @Configuration  
 //@ConditionalOnClass(SBASampleImpl.class)  
 @ConditionalOnProperty(name="mode", havingValue="false")  
 public class SBASampleConfiguration {  
        
      @Bean  
      public SBASampleInterface getSBAService() {  
             
           return new SBASampleImpl();  
      }  
 }  
 
Please go ahead and add the property 'mode=false' in your application.properties If this property is not present or has a different value, your server will refuse to start as there will be not property present to inject for an autowired bean. (Refer to the code in the GitHub Repository).






With Spring DevTools Enabled, you will see one such log on the console that are the debug statements showing the matches or evaluations against the conditions.


@ConfigurationProperties
@ConfigurationPropertiesScan
It marks a class as a configuration properties source (mapping it from a properties or yaml file), which can then be used to control and also to validate properties. ConfigurationPropertiesScan can be used to scan locations for property files. The location can be specified as the parameter to the annotation.

 package xyz.sumithpuri.spring.boot.annotation.configuration;  
   
 import org.springframework.boot.context.properties.ConfigurationProperties;  
 import org.springframework.boot.context.properties.ConfigurationPropertiesScan;  
 import org.springframework.stereotype.Component;  
   
 /**  
  * @author sumith.puri  
  *  
  */  
 @Component  
 @ConfigurationProperties(prefix = "proptest")  
 @ConfigurationPropertiesScan  
 public class SBASampleConfigurationProperties {  
   
      private String name;  
      private String pass;  
      private String mail;  
      private String year;  
      private long uuid;  
   
      public String getName() {  
           return name;  
      }  
   
      public void setName(String name) {  
           this.name = name;  
      }  
   
     ..... // Getter and Setter Methods 

[Typical Properties File to be Read By ConfigurationProperties]










[Debug Print Messages on Invocation of a Controller Endpoint]














[Reference Links]
https://github.com/Buzzardo/spring-docs/blob/master/annotation-cheat-sheet.adoc
https://javasterling.com/java/spring-boot-annotations/

No comments: