35 Essential Spring Boot Annotations for Faster Development
By Rohan Vats
Updated on Apr 04, 2025 | 38 min read | 139.5k views
Share:
For working professionals
For fresh graduates
More
By Rohan Vats
Updated on Apr 04, 2025 | 38 min read | 139.5k views
Share:
Table of Contents
You might have spent hours configuring your Spring application in the past, dealing with countless XML lines just to set up a few beans. That's where Spring Boot annotations come in. Instead of complicated XML files, you now have annotations that handle all the heavy lifting for you. Attaching specific annotations tells Spring Boot exactly how to handle components and configurations behind the scenes.
Boost your career by mastering cutting-edge technology! Enroll in Artificial Intelligence & Machine Learning Courses and stay ahead in the evolving tech industry.
Here are a few reasons Spring Boot annotations matter:
This blog will teach you about stereotypes that mark classes for specific roles, property-based annotations that manage external settings, and advanced conditional annotations.
Spring Boot offers a collection of annotations that guide how an application’s components behave and interact with one another. You can handle core configurations, manage bean lifecycles, define request handling endpoints, and more.
Take your skills to the next level with industry-leading AI and Machine Learning programs:
Take a look at the table below to see the major categories and where each annotation in Java Spring Boot fits.
Spring Boot Annotations Category |
Spring Boot Annotations List |
Core Configuration Annotations | 1. @SpringBootApplication 2. @EnableAutoConfiguration 3. @SpringBootConfiguration 4. @ComponentScan 5. @Configuration |
Bean Creation and Management | 6. @Bean 7. @Component 8. @Service 9. @Repository |
Request Handling and Controller | 10. @Controller 11. @RestController 12. @RequestMapping 13. @GetMapping / @PostMapping / @PutMapping / @DeleteMapping 14. @PathVariable 15. @RequestParam 16. @RequestBody / @ResponseBody |
Dependency Injection and Properties | 17. @Autowired 18. @Qualifier 19. @Value |
Conditional Annotations | 20. @ConditionalOnClass 21. @ConditionalOnMissingClass 22. @ConditionalOnBean 23. @ConditionalOnMissingBean 24. @ConditionalOnProperty 25. @ConditionalOnResource 26. @ConditionalOnWebApplication 27. @ConditionalOnNotWebApplication 28. @ConditionalOnExpression 29. @ConditionalOnCloudPlatform 30. @Conditional |
Profile-Based Annotation in Java Spring Boot | 31. @Profile |
Handling Configuration Properties | 32. @ConfigurationProperties 33. @EnableConfigurationProperties |
Error Handling Annotations | 34. @ControllerAdvice 35. @ExceptionHandler |
Take the leap into Spring Boot and DevOps with upGrad’s comprehensive software engineering courses today!
Also Read: Top Spring Boot Features for Java Developers
When you begin a Spring Boot project, core configuration Spring Boot annotations help you organize essential details so your application can run without extra effort.They handle tasks like automatic bean creation, scanning the correct packages, and keeping your main class as streamlined as possible.
Take a look at how these configurations come together:
Now, let’s explore the annotations in detail.
You rely on @SpringBootApplication to unify three vital Spring Boot features under one annotation. It brings together the following:
Placing this annotation in Java Spring Boot on your main class streamlines the entire configuration process. It also makes your application's entry point obvious, simplifying maintenance and onboarding as your project grows.
Here’s how it distinguishes itself:
Sample Example of @SpringBootApplication in Action
Below is a brief example to demonstrate how this single annotation simplifies a core setup. Notice how everything from bean configuration to component scanning is activated under the hood:
@SpringBootApplication
public class SarikaApplication {
public static void main(String[] args) {
SpringApplication.run(SarikaApplication.class, args);
}
}
In this snippet, @SpringBootApplication ensures that configuration, auto-configuration, and component scanning run automatically. You no longer have to specify each annotation individually or rely on extensive XML files.
@EnableAutoConfiguration automates much of the setup required for Spring Boot applications. This annotation inspects your classpath and brings in the configurations that align with the dependencies you’ve added. It spares you from manually defining each piece of the puzzle — so your project benefits from what’s already present.
You then spend less time on infrastructure and more time refining the unique features of your application.
Here’s why it makes a difference:
Sample Example of @EnableAutoConfiguration in Action
Below is a short code example. Notice that @EnableAutoConfiguration takes care of enabling any features you have placed on your classpath:
@Configuration
@EnableAutoConfiguration
public class RohanAutoConfig {
// Beans and additional settings can go here
}
This snippet shows how the annotation checks what your project includes. If you have a MySQL driver, it configures a data source. If you add web dependencies, it sets up MVC components. Thanks to auto-configuration, you don't write those lines yourself.
You can use @SpringBootConfiguration in scenarios that call for a class dedicated to Spring Boot–specific settings. It still indicates a source of bean definitions (like @Configuration does) but also flags that this configuration ties directly into Spring Boot’s internal processes. You might not see it as commonly because @SpringBootApplication often covers its functionality, but it remains an option.
Here’s what stands out:
Sample Example of @SpringBootConfiguration in Action
Below is a code example. Notice how you can still define beans exactly like you do with regular configuration classes:
@SpringBootConfiguration
public class MeenaBootConfig {
@Bean
public String greeting() {
return "Hello from a Boot-specific config class!";
}
}
Here, you see how this annotation makes your class recognizable as a source of Spring Boot configuration. The methods you mark as beans are picked up automatically when your application starts.
You rely on @ComponentScan to tell Spring which packages contain the components you want to manage. It spares you from individually declaring each class that should be a bean, bringing them all into your application context. If you’re organizing multiple packages, you can list them here so nothing is overlooked.
Here are the key points you must know about this annotation in Java Spring Boot:
Sample Example of @ComponentScan in Action
See the example below. Notice how you can point to a specific package or multiple packages:
@Configuration
@ComponentScan(basePackages = {"com.example.raviapp", "com.example.helpdesk"})
public class RaviAppConfig {
// Additional setup logic
}
In this snippet, classes marked with stereotype annotations in the com.example.raviapp and com.example.helpdesk packages become beans automatically. You don’t write extra lines to register them.
You rely on @Configuration to create a class that declares one or more beans. This straightforward, code-based approach replaces the verbose XML files of older Spring versions. By grouping related beans in the same configuration class, you keep them easy to find and maintain.
Consider the following benefits:
Sample Example of @Configuration in Action
The example below shows how you might declare a bean in a simple config file. You’ll see how @Configuration becomes the root that allows @Bean to work:
@Configuration
public class TinaConfiguration {
@Bean
public MessageService messageService() {
return new WhatsAppService();
}
}
This snippet illustrates how any method tagged with @Bean is recognized as a Spring bean. The Spring container manages its lifecycle without further intervention from you.
Also Read: Spring vs Spring Boot: Understanding the Difference Between Spring and Spring Boot in 2025
Bean creation and management ensure that your objects are well-organized, automatically instantiated, and supervised by the Spring container. The four annotations in this section have a unique job, whether it’s marking classes for discovery, defining service logic, or handling persistence. In short, these annotations highlight the distinct roles of each class while saving you from configuring everything by hand.
Here’s a glimpse of what these annotations offer:
Next, you will see these annotations broken down individually so you can decide exactly how each one might strengthen your application’s structure.
You use @Bean to declare a method whose return value will be managed as a bean in the Spring container. It allows you to replace large XML chunks with straightforward Java code. When Spring discovers this annotation on a method, it automatically invokes that method to retrieve the resulting bean instance. This setup eliminates unnecessary verbosity and keeps the essence of each bean front and center.
Here’s why it works well:
Sample Example of @Bean in Action
The snippet below demonstrates a typical usage. Notice how @Bean is placed on a method that returns a specific object:
@Configuration
public class PriyaConfiguration {
@Bean
public PaymentProcessor paymentProcessor() {
return new UpiPaymentProcessor();
}
}
In this example, paymentProcessor() becomes a bean named paymentProcessor. Spring will control its lifecycle, inject it wherever needed, and free you from writing additional boilerplate code.
You rely on @Component to mark a class that should be picked up by Spring’s component scanning mechanism. It is the foundation for more specialized annotations like @Service and @Repository. By annotating a class with @Component, you declare that it is a candidate for auto-detection and automatic instantiation.
Here’s what makes it helpful:
Sample Example of @Component in Action
Check out the following snippet. Notice how @Component alone is enough to let Spring pick up the class:
@Component
public class VinayLogger {
public void logMessage(String message) {
System.out.println("[VinayLogger] " + message);
}
}
In this case, VinayLogger is discovered during component scanning and turned into a bean without any additional configuration. You simply call it wherever you want a logging helper.
You typically apply @Service when a class holds your business logic or application functionality. It’s a more specialized version of @Component, indicating that the core purpose of this class lies in performing operations or calculations, often in coordination with repositories or external APIs.
Marking a class with @Service keeps your application organized in a layered format, where controllers handle requests, services perform logic, and repositories manage data.
Here are the key reasons to use it:
Sample Example of @Service in Action
In the snippet below, you’ll see how @Service fits right into the flow between controllers and repositories:
@Service
public class AnkitaOrderService {
public String placeOrder(String productName) {
// Some business logic, e.g., check inventory, apply discount
return "Order placed for " + productName;
}
}
This code clarifies that AnkitaOrderService is part of the service layer, making it simpler to see where business logic resides when you read through the application.
You rely on @Repository to define a class responsible for data-related operations, whether you’re using JPA, JDBC, or another data access tool. This annotation signals to Spring that you want consistent handling of exceptions and auto-detection of your persistence classes.
It’s a specialization of @Component with added database-oriented features, so it fits neatly into applications that need clear separation between business logic and data management.
Here are some of its notable points:
Sample Example of @Repository in Action
Below is an example of how you might apply @Repository. Notice that Spring recognizes it as a class that deals specifically with data storage:
@Repository
public interface TicketRepository extends JpaRepository<Ticket, Long> {
List<Ticket> findBySeatCategory(String category);
}
Here, TicketRepository inherits database operations from JpaRepository, and Spring sees it as part of the data layer. This separates it from your service logic and avoids confusion over the class’s purpose.
Want to learn more about Spring Boot and development? Then join upGrad’s Full Stack Bootcamp today!
When you build a web application, your code needs to listen for incoming calls, process the details, and send back a suitable response. Request handling annotations in Spring Boot define which class or method is responsible for specific URLs, allowing you to map each path or action with precision.
In many cases, you can automatically parse query parameters, path segments, and even entire request bodies into Java objects. This approach transforms what could be complex routing logic into well-organized methods that are easy to read and maintain.
Let’s examine how these request mapping and controller annotations guide your application logic:
Up next, you’ll get an in-depth look at these annotations so you can adapt them to your own needs.
You rely on @Controller when you develop a web application that returns views rather than JSON responses. This annotation informs Spring that the class handles incoming requests, often linking them to a template engine such as Thymeleaf or JSP. Organizing your code around these controllers keeps related actions and routes in one place.
Here are the key benefits of this annotation in Java Spring Boot:
Sample Example of @Controller in Action
Below is a small example. Notice how the method returns a view name, and Spring decides which template to use:
@Controller
public class AdityaController {
@RequestMapping("/greeting")
public String showGreetingPage(Model model) {
model.addAttribute("msg", "Hello from AdityaController!");
return "greeting"; // Points to a template named greeting
}
}
In this snippet, showGreetingPage receives a request for /greeting, sets a message for the view, and returns the name of a template to render.
Use @RestController when you want to produce data — commonly JSON — directly from your endpoints. It fuses @Controller with @ResponseBody, which means you no longer return a view name. Instead, you provide an object or string that Spring automatically writes to the HTTP response body. This approach suits applications that operate as APIs.
Here are some of the most important highlights of this annotation in Java Spring Boot:
Sample Example of @RestController in Action
The example below shows how returning data in JSON becomes natural. Notice you skip any template-based rendering:
@RestController
@RequestMapping("/api")
public class RaviRestController {
@GetMapping("/products")
public List<String> getProducts() {
return List.of("Laptop", "Smartphone", "Camera");
}
}
Here, RaviRestController serves a JSON list of products to requests on /api/products. You don’t attach view names or manage a model object for HTML content.
You use @RequestMapping to connect a specific HTTP path with a handler method or class. It tells Spring, “When a request arrives for this path, please call this method.” You can apply it at both the class level (for a base URL) and method level (for more detailed paths).
Here are the key reasons to use it:
Sample Example of @RequestMapping in Action
Below is a short code snippet. Notice how one path method can differ from another in the same controller:
@Controller
@RequestMapping("/catalog")
public class ShrutiCatalogController {
@RequestMapping("/electronics")
public String showElectronics(Model model) {
model.addAttribute("items", List.of("TV", "Headphones"));
return "electronicsPage";
}
@RequestMapping("/books")
public String showBooks(Model model) {
model.addAttribute("items", List.of("Novel", "Comic"));
return "booksPage";
}
}
In this snippet, any request that starts with /catalog routes to ShrutiCatalogController. Each method then responds to a more specific path, such as /catalog/electronics.
You choose these Spring Boot annotations for more explicit matching of HTTP methods. Each one tells Spring exactly which verb a handler method should respond to, which cuts down on repetition in your code. Instead of writing @RequestMapping(value = "/items", method = RequestMethod.GET), you say @GetMapping("/items").
Key uses:
Sample Example
Below is an example. Notice how each request uses an annotation matching its HTTP action:
@RestController
@RequestMapping("/users")
public class DeveshUserController {
@GetMapping
public List<String> getAllUsers() {
return List.of("Rahul", "Meera");
}
@PostMapping
public String createUser(@RequestBody String userName) {
return userName + " created successfully!";
}
}
Here, getAllUsers() listens for GET requests on /users, while createUser() listens for POST requests on the same path.
Also Read: HTTP Get Method and Post Method
Apply @PathVariable when the identifier appears right in the URL path, such as /product/123. Instead of a query parameter, you rely on the path segment to carry the necessary information. Spring automatically parses that portion of the URL and passes it to your method.
Here are some significant points about this annotation in Java Spring Boot:
Sample Example of @PathVariable in Action
See the snippet below. Notice how @PathVariable("orderId") picks up the numeric segment and stores it in the orderId parameter:
@RestController
@RequestMapping("/orders")
public class AnuOrderController {
@GetMapping("/{orderId}")
public String getOrderDetails(@PathVariable("orderId") Long orderId) {
return "Details for order " + orderId;
}
}
In this example, a request to /orders/20 calls getOrderDetails() with orderId equal to 20.
You call on @RequestParam to retrieve query parameters from the request URL, such as /search?keyword=laptop. This annotation identifies a query parameter by name and then maps it to a method parameter. You can make it required or assign a default value for scenarios when it’s not specified in the request.
Reasons to choose it:
Sample Example of @RequestParam in Action
Here’s an example. Notice how @RequestParam aligns the URL parameter with the method argument:
@RestController
@RequestMapping("/search")
public class PoojaSearchController {
@GetMapping
public String findResults(@RequestParam(name="keyword", defaultValue="mobile") String keyword) {
return "You searched for: " + keyword;
}
}
In this snippet, if the keyword doesn’t appear in the query string, Spring will treat it as "mobile" by default.
You rely on @RequestBody to bind the body of an incoming HTTP request to a method parameter. Spring translates the JSON or XML into a Java object.
Meanwhile, @ResponseBody applies to a method that directly returns a Java object, which Spring then converts into JSON or XML in the response body. @RestController implicitly uses @ResponseBody on every method, so it’s common when building APIs.
Here are the core points to remember:
Sample Example of @RequestBody / @ResponseBody in Action
Check out the following snippet. Notice that @RequestBody converts incoming JSON into a User object, and returning User with @ResponseBody sends JSON back:
@RestController
@RequestMapping("/accounts")
public class SameerAccountController {
@PostMapping
public @ResponseBody User createAccount(@RequestBody User newUser) {
// Simulate saving
newUser.setId(100L);
return newUser;
}
}
In this code, the user data arrives as JSON, Spring maps it to a User object, and you return that object, which goes back to JSON for the client.
You might want certain classes to be automatically available in your code without writing manual new statements, or you might prefer reading important details — like port numbers or API keys — from property files instead of hardcoding them. Dependency injection and property-based Spring Boot annotations handle these needs for you.
They simplify your classes and let you adjust values outside your code when requirements change later. It all comes down to managing resources, application settings, and object lifecycles in a seamless way.
Consider the following main benefits:
Up next, you’ll see how each annotation addresses a different aspect of dependency injection and property management.
You can let Spring handle object creation and linking for you by marking fields or constructors with @Autowired.
Autowired in Spring Boot looks for an available bean of a matching type and automatically assigns it. This spares you the trouble of manually instantiating dependencies in your classes and helps keep each class focused on its core responsibilities instead of a boilerplate setup.
Here are its main strengths:
Sample Example of @Autowired in Action
Below is a brief code example. Note how the constructor injection style offers clarity:
@Service
public class PriyaNotificationService {
private final UserRepository userRepository;
@Autowired
public PriyaNotificationService(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
Here, PriyaNotificationService gets an instance of UserRepository without you calling new UserRepository(). Spring identifies the right bean and wires it in at startup so you stay focused on the service’s main logic.
You may prefer @Qualifier when you have more than one bean of the same type and want to pick a specific one. Perhaps you define multiple payment gateways or loggers, and each serves a unique purpose. Marking your bean with @Qualifier("identifier") helps Spring know exactly which bean to inject in your class.
Here are some key points about this annotation in Java Spring Boot:
Sample Example of @Qualifier in Action
Here is a simple code example. Notice how you pick the right bean for your class:
@Service("smsService")
public class SmsAlertService {
// ...
}
@Service("emailService")
public class EmailAlertService {
// ...
}
@Service
public class AlertManager {
private final AlertService service;
@Autowired
public AlertManager(@Qualifier("smsService") AlertService service) {
this.service = service;
}
}
In this snippet, two beans share an AlertService interface, but AlertManager depends on the one labeled "smsService". By attaching @Qualifier("smsService"), you confirm which bean to use.
You can keep your configuration flexible by reading values from .properties or .yml files using @Value. Rather than hard coding things like URLs, passwords, or feature toggles, you store them externally and bind them at runtime. This setup adapts easily to different environments, so you don’t have to rebuild whenever you change a setting.
Here are some crucial benefits of this annotation:
Sample Example of @Value in Action
Below is a code sample. Observe how a single field references a property key:
@RestController
public class FeedbackController {
@Value("${feedback.email:help@myapp.com}")
private String feedbackEmail;
@GetMapping("/feedbackContact")
public String getFeedbackEmail() {
return "Please send feedback to: " + feedbackEmail;
}
}
In this snippet, if you don’t define feedback.email in your property files, Spring will use "help@myapp.com" as a fallback. This approach keeps your configuration flexible and helps you alter environment details quickly.
Learn more about Spring Boot and its use in Java with upGrad’s free Core Java Basics course today!
Sometimes, you want a piece of logic to activate only if certain conditions are met, like the presence of a specific dependency or a property set to a particular value. Conditional annotations keep your application from loading anything you don’t actually need, which can streamline performance and reduce clutter.
Each annotation checks for a unique factor — be it a class in the classpath or a property’s value — before deciding whether to bring certain beans or configurations to life. This results in an application that adapts to different environments, libraries, and preferences with very little manual effort.
Here are a few core strengths conditional annotations provide:
Next, you will find each of these annotations broken down, revealing how they determine the right time to enable or bypass particular configurations.
You can use @ConditionalOnClass when a certain Java class or library must be present on the classpath before activating a bean or configuration. This annotation in Java Spring Boot checks for that presence during startup and only proceeds if the class is detected. It’s especially helpful when your code depends on optional libraries that might not always be installed.
Here are some key points you must know about this annotation:
Sample Example of @ConditionalOnClass in Action
Below is an example. Notice how the configuration appears only if org.postgresql.Driver exists:
@Configuration
@ConditionalOnClass(name = "org.postgresql.Driver")
public class PostgresAutoConfig {
@Bean
public DataSource postgresDataSource() {
// Return configured DataSource for PostgreSQL
return new HikariDataSource();
}
}
In this snippet, PostgresAutoConfig becomes active only if the PostgreSQL driver is on the classpath. If you leave that library out, Spring ignores this configuration.
You can turn to @ConditionalOnMissingClass when you want a bean or configuration to load, but only if a particular class is not found on the classpath. This annotation fits a scenario where you plan to supply a fallback option if a primary dependency is absent.
Consider these benefits:
Sample Example of @ConditionalOnMissingClass in Action
Here’s a small code snippet. Notice how it checks for a class name and loads the fallback configuration if that class is absent:
@Configuration
@ConditionalOnMissingClass(value = "com.legacy.LegacyDriver")
public class ModernDbConfig {
@Bean
public DataSource modernDataSource() {
// Return an alternative data source
return new HikariDataSource();
}
}
With this setup, ModernDbConfig only activates when com.legacy.LegacyDriver isn’t around, ensuring you don’t overlap conflicting drivers.
You might use @ConditionalOnBean if your new configuration or bean should load only when another specific bean already exists. It’s common in layered setups where one bean relies on another’s presence for correct operation.
Here are some of its key purposes:
Sample Example of @ConditionalOnBean in Action
Below is an example. Notice how @ConditionalOnBean references a bean type:
@Configuration
public class AnalyticsConfig {
@Bean
@ConditionalOnBean(UserService.class)
public AnalyticsService analyticsService() {
return new AnalyticsService();
}
}
In this snippet, if UserService isn’t found, analyticsService() won’t load. This helps avoid partial setups that can cause runtime errors.
Use @ConditionalOnMissingBean when you want Spring to load a bean only if a certain bean isn’t already present. It’s especially useful for setting defaults that anyone can override. If someone else defines a bean of the same type or name, your fallback bean stays out of the way.
Check out these key highlights about this annotation in Java Spring Boot:
Sample Example of @ConditionalOnMissingBean in Action
Below is a code snippet. Notice that a default user service bean will load only if none other exists:
@Configuration
public class DefaultUserConfig {
@Bean
@ConditionalOnMissingBean(UserService.class)
public UserService defaultUserService() {
return new BasicUserService();
}
}
If a different UserService bean is present, Spring ignores defaultUserService(). That way, you can still rely on it if no custom version exists.
upGrad’s Exclusive Software and Tech Webinar for you –
SAAS Business – What is So Different?
Rely on @ConditionalOnProperty if a particular property key or a specific value in your configuration determines whether a bean should load. This annotation in Java Spring Boot reads application properties and decides if the logic stays active based on a match.
Points of interest:
Sample Example of @ConditionalOnProperty in Action
Below is a sample code block. Notice how it checks a property’s name and value:
@Configuration
public class FeatureToggles {
@Bean
@ConditionalOnProperty(name = "feature.advancedMode", havingValue = "true")
public AdvancedService advancedService() {
return new AdvancedService();
}
}
Here, if feature.advancedMode=true, you enable AdvancedService. If someone sets it to false in application.properties, Spring skips that bean.
You choose @ConditionalOnResource when the existence of a resource file (like a configuration file or image) decides if a certain config should load. It ties the presence of that file on the classpath to your bean creation.
Here are the key aspects of this annotation in Java Spring Boot that you must know:
Sample Example of @ConditionalOnResource in Action
Below is an example. Notice how it checks the presence of a file before setting up the bean:
@Configuration
public class ResourceDrivenConfig {
@Bean
@ConditionalOnResource(resources = "classpath:reports.yaml")
public ReportService reportService() {
return new ReportService();
}
}
With this condition, if reports.yaml isn’t in the classpath, Spring will ignore reportService(). That helps avoid file-not-found errors.
Turn to @ConditionalOnWebApplication when you want a bean or configuration to load only in a web setting. This annotation checks if your application runs in a web environment, meaning it can handle HTTP requests and responses. It’s perfect for beans that rely on HTTP details.
Here’s why it helps:
Sample Example of @ConditionalOnWebApplication in Action
Below is an example. Notice how it ensures a web-based configuration:
@Configuration
public class WebSecurityConfig {
@Bean
@ConditionalOnWebApplication
public SecurityFilter webSecurityFilter() {
return new SecurityFilter();
}
}
If you’re not running a web context, webSecurityFilter() does not appear in the application context.
Use @ConditionalOnNotWebApplication for the reverse scenario: You need certain beans only if the application does not run as a web service. This approach helps you avoid configuring servlets, web filters, or other HTTP-related items in a standalone or batch application.
Consider its value:
Sample Example of @ConditionalOnNotWebApplication in Action
Below is a snippet. Notice how the bean is only relevant if there’s no web context:
@Configuration
public class ConsoleConfig {
@Bean
@ConditionalOnNotWebApplication
public ConsoleLogger consoleLogger() {
return new ConsoleLogger();
}
}
If the application starts as a web server, consoleLogger() is skipped. That avoids injecting console-related beans where they aren’t required.
You can harness @ConditionalOnExpression to evaluate a SpEL (Spring Expression Language) string and decide if a bean or config should load. This is handy when you want more complex checks that go beyond just detecting a property or file — maybe arithmetic or combining multiple conditions.
Here’s what you can do:
Sample Example of @ConditionalOnExpression in Action
Below is a simple code example. Notice the annotation runs a quick SpEL check before loading the bean:
@Configuration
public class ExpressionConfig {
@Bean
@ConditionalOnExpression("${feature.x} == true and ${system.mode} == 'advanced'")
public XAdvancedBean xAdvancedBean() {
return new XAdvancedBean();
}
}
If both conditions match — feature.x is true, and system.mode is 'advanced' — then xAdvancedBean() is activated. Otherwise, Spring ignores it.
Use @ConditionalOnCloudPlatform when you want a configuration to load only if your application runs on a specified cloud platform, such as Cloud Foundry. It checks the environment and ensures you bring in the right settings for that hosting service.
Here are a few key points about this annotation in Java Spring Boot:
Sample Example of @ConditionalOnCloudPlatform in Action
Below is an example snippet. Notice it ties the logic to a named platform:
@Configuration
@ConditionalOnCloudPlatform(CloudPlatform.CLOUD_FOUNDRY)
public class CloudFoundryConfig {
@Bean
public LoggingService cfLoggingService() {
return new LoggingService();
}
}
This code only takes effect if your application is running in a Cloud Foundry environment. If you deploy elsewhere, the configuration stays dormant.
@Conditional is the most generic form of conditional annotation in Java Spring Boot. You provide a custom Condition class that implements logic in the matches method, which either allows or blocks the configuration. This is your fallback if none of the other condition annotations meet a specific scenario.
Here are a few important details:
Sample Example of @Conditional in Action
Below is an example. Notice how your condition class can hold advanced checks:
@Configuration
@Conditional(WindowsCheck.class)
public class WindowsOnlyConfig {
@Bean
public WindowsHelper windowsHelper() {
return new WindowsHelper();
}
}
// Condition class:
public class WindowsCheck implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return System.getProperty("os.name").toLowerCase().contains("win");
}
}
Here, WindowsOnlyConfig activates if your custom WindowsCheck class returns true. It grants total flexibility for deciding how to run your application under special circumstances.
You might want some features to work differently depending on whether you’re using a local setup or deploying to a hosting service. That’s where the concept of profiles becomes useful: you organize beans or configurations so that they only activate under a specific label, such as “dev” or “prod.”
By grouping settings like database credentials or debugging switches in this way, you can keep a single codebase that neatly adapts to each environment.
Now, take a quick look at how profiles boost flexibility:
Next, you’ll see how the @Profile annotation fulfills these ideas by cleanly dividing your application into tailored configurations.
When your application needs different behavior in development, staging, or production, you can mark entire classes or bean definitions with @Profile. Attaching this label ensures those configurations only load if that profile is activated.
This mechanism works well for environment-specific database connections, logging levels, or third-party integrations. Rather than duplicating your entire codebase, you keep it all in one place and let Spring pick which beans to load based on the selected profile.
Let’s break down how this annotation makes multiple environments easier:
Sample Example of @Profile in Action
Below is a quick code snippet. Notice how the annotation on each configuration class or bean ensures they appear only under the specified label:
@Configuration
@Profile("dev")
public class DevDatabaseConfig {
@Bean
public DataSource devDataSource() {
// Return a DataSource pointing to your dev environment
return new HikariDataSource();
}
}
@Configuration
@Profile("prod")
public class ProdDatabaseConfig {
@Bean
public DataSource prodDataSource() {
// Return a DataSource pointing to your prod environment
return new HikariDataSource();
}
}
Here, when you launch the application with spring.profiles.active=dev, Spring picks the DevDatabaseConfig. If you change it to prod, Spring loads the ProdDatabaseConfig. This approach keeps environment-specific logic in distinct files, simplifying updates and troubleshooting later.
When your application starts growing, you might prefer keeping settings such as URLs, ports, or custom toggles in external property files instead of embedding them in your code. This practice makes it simpler to modify or replace configurations without affecting the logic of your classes.
You also maintain a clear separation between business code and environment-based variables, which helps when you switch from one runtime setting to another.
Here are a few reasons these property-based annotations prove valuable:
Let’s get started with the annotation now.
You can attach @ConfigurationProperties to a class that holds external values such as URLs, user credentials, or timeouts. This approach provides type safety because each field in your class matches up with a specific property key. In addition, you keep these fields organized under a prefix, which makes it clear which part of your application the properties belong to.
Here’s how this annotation in Java Spring Boot promotes clarity in your project:
Sample Example of @ConfigurationProperties in Action
Below is a typical code snippet for @ConfigurationProperties. Notice how the prefix corresponds to keys in your property files:
@ConfigurationProperties(prefix = "mail")
public class MailConfigProps {
private String host;
private int port;
private String username;
private String password;
// Getters and setters omitted for brevity
}
When you define mail.host, mail.port, and so on in your .properties or .yml, Spring populates these fields automatically, saving you from writing multiple @Value statements.
Use @EnableConfigurationProperties to activate classes annotated with @ConfigurationProperties. Without it, your property-binding class might remain undiscovered. By telling Spring to look for one or more @ConfigurationProperties classes, you ensure these fields are recognized and properly bound during startup.
Take a quick look at what this annotation contributes:
Sample Example of @EnableConfigurationProperties in Action
See the snippet below. Notice how it references the class containing your properties:
@Configuration
@EnableConfigurationProperties(MailConfigProps.class)
public class MailAutoConfig {
@Bean
public MailService mailService(MailConfigProps props) {
// Use props.getHost(), props.getPort() to set up your service
return new MailService(props.getHost(), props.getPort());
}
}
Here, @EnableConfigurationProperties(MailConfigProps.class) ensures MailConfigProps becomes a bean whose values are injected from your external files. You then take those values and pass them to a MailService, keeping your code free from hardcoded settings.
Whether you work on a small web app or a large enterprise platform, dealing with unexpected issues is unavoidable. Spring Boot provides built-in annotations that let you define a central spot for exception handling while allowing you to manage individual errors at a more fine-grained level.
This setup prevents scattered try-catch blocks and promotes cleaner, more predictable responses when something goes wrong.
Before diving into the specific Spring Boot annotations list, let’s see why this centralized approach pays off:
Let’s check out the annotations now.
You can mark a class with @ControllerAdvice to handle errors and specific outcomes across multiple controllers in one place. This annotation in Java Spring Boot frees each controller from having its own exception-handling methods and gives you a single spot to set up responses for different error types.
You keep your controllers cleaner and maintain a clear view of how your application manages unexpected events.
Let’s look at how this annotation helps you keep your error handling organized:
Sample Example of @ControllerAdvice in Action
Below is a short example. Notice how this advice class offers a method for catching a specific exception:
@ControllerAdvice
public class GlobalErrorAdvisor {
@ExceptionHandler(NullPointerException.class)
public ResponseEntity<String> handleNullPointer(NullPointerException ex) {
return new ResponseEntity<>("An unexpected issue occurred.", HttpStatus.BAD_REQUEST);
}
}
Here, GlobalErrorAdvisor catches any NullPointerException that happens in any controller. You can add more methods to handle additional exceptions as you see fit.
You place @ExceptionHandler on methods that react to specific exceptions. This annotation can live inside a regular controller or in a class annotated with @ControllerAdvice for centralized error handling.
It helps you define one method per exception type, leading to simpler code than try-catch blocks sprinkled around your entire project.
Check out how this annotation in Java Spring Boot streamlines error handling:
Sample Example of @ExceptionHandler in Action
Here’s an example. Notice how @ExceptionHandler specifies the exception it catches:
@RestController
public class PaymentController {
@PostMapping("/pay")
public String processPayment(@RequestBody PaymentRequest request) {
// Possibly throws a custom exception
return "Payment processed!";
}
@ExceptionHandler(InvalidPaymentException.class)
public ResponseEntity<String> handleInvalidPayment(InvalidPaymentException ex) {
return new ResponseEntity<>("Payment failed: " + ex.getMessage(), HttpStatus.UNPROCESSABLE_ENTITY);
}
}
In this snippet, handleInvalidPayment only responds if InvalidPaymentException surfaces in PaymentController. You gain precision by specifying distinct methods for each possible exception, rather than mixing different error types into a single handler.
Many Spring Boot annotations appear to do similar things, but each one carries a specific responsibility. You avoid confusion by applying the right annotation in the right context. That means you skip overlapping markers on the same class and aim to keep your codebase understandable over time.
It also keeps your configuration consistent so any team member can make adjustments without breaking your setup.
Here are a few strategies to keep your annotations organized and purposeful:
upGrad offers top-notch programs to help you master Spring Boot Annotations and advance your development skills.
Here are some of the most popular courses:
Boost your skills — enroll in upGrad’s programs today and excel in Spring Boot development! Get personalized career counseling from upGrad’s experts to help you choose the right program for your goals. You can also visit your nearest upGrad offline Career Center to kickstart your future!
Boost your career with our popular Software Engineering courses, offering hands-on training and expert guidance to turn you into a skilled software developer.
Master in-demand Software Development skills like coding, system design, DevOps, and agile methodologies to excel in today’s competitive tech industry.
Stay informed with our widely-read Software Development articles, covering everything from coding techniques to the latest advancements in software engineering.
Get Free Consultation
By submitting, I accept the T&C and
Privacy Policy
India’s #1 Tech University
Executive PG Certification in AI-Powered Full Stack Development
77%
seats filled
Top Resources