Are you prepared for questions like 'Describe the use of @RestController annotation.' and similar? We've collected 40 interview questions for you to prepare for your next Spring interview.
The @RestController annotation in Spring is a shorthand for combining @Controller and @ResponseBody. It simplifies the creation of RESTful web services by converting the return value of each method to a JSON response. When you annotate a class with @RestController, you eliminate the need to annotate every method with @ResponseBody, which makes your code cleaner and more concise. Essentially, it tells Spring to treat the class as a controller where every method returns a domain object instead of a view.
Spring Framework is a comprehensive framework for Java development, providing infrastructure support at the application level to facilitate creating high-performing, easily testable, and reusable code. It's well-known for its dependency injection, which helps in loosely coupling components and simplifying unit testing.
Some of its main features include:
Spring Boot simplifies Spring application development by eliminating the need for extensive configuration. It provides a range of out-of-the-box functionalities, such as embedded servers, default configurations, and pre-built templates, which allows developers to get up and running quickly without needing to manually configure everything from scratch. With features like Spring Boot Starters, it also offers convenient dependency management by bundling commonly used libraries and frameworks into lightweight packages. This streamlined approach lets you focus on writing your business logic rather than dealing with boilerplate code and configuration tasks.
Did you know? We have over 3,000 mentors available right now!
Spring MVC is synchronous and follows a one-request-per-thread model, which is well-suited for traditional web applications. It uses the Servlet API and is blocking by design, meaning each request is handled by a dedicated thread until the response is ready.
Spring WebFlux, on the other hand, is asynchronous and non-blocking, using a reactive programming model. It can handle many more concurrent connections with fewer resources by using event loops and is built on the Reactor project. This makes it ideal for applications that require high scalability and responsiveness, such as real-time applications.
Spring handles scheduling tasks using the @Scheduled
annotation and the TaskScheduler
interface. You can use the annotation to define when a particular method should run, specifying intervals in a cron-like syntax or as fixed delays or fixed rates. For more complex needs, such as dynamic scheduling or external configuration, you can implement a SchedulingConfigurer
to customize task scheduling. The underlying mechanism relies on thread pools managed by Spring to ensure tasks run efficiently and concurrently.
Creating custom annotations in Spring involves defining the annotation with @interface
and then using it where needed. You can also add meta-annotations like @Component
, @Configuration
, etc., to integrate them within the Spring context. For example, you might create a custom annotation for a special component:
java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface MyCustomComponent {
String value() default "";
}
Then you can use @MyCustomComponent
in your Spring beans which you'd like to mark with that annotation. Spring will treat those classes as components if it's properly configured for component scanning. Functionally, you can also create custom annotations to handle aspects, for example, by combining with Spring AOP to add behaviors like logging or transaction management.
java
@Aspect
@Component
public class MyCustomAspect {
@Before("@within(MyCustomComponent)")
public void beforeAdvice(JoinPoint joinPoint) {
// implement the advice logic
}
}
This sets up a before advice that's triggered for all methods within classes annotated with @MyCustomComponent
.
Message converters in Spring MVC are used to handle the conversion between HTTP requests and responses and Java objects. When a request comes in, a message converter can read the request body and convert it to a POJO (Plain Old Java Object) that the controller can work with. Similarly, when a controller returns data, a message converter can take this data and convert it into an appropriate response format like JSON or XML. This process allows for a seamless handling of data formats and is essential for RESTful APIs. Various message converters are available in Spring, such as MappingJackson2HttpMessageConverter
for JSON and Jaxb2RootElementHttpMessageConverter
for XML.
Spring IoC (Inversion of Control) is a principle where the control of object creation and management is given to the container instead of the developer. Essentially, the framework handles the lifecycle and configuration of application objects, making the code more modular and easier to test.
Dependency Injection (DI) is a design pattern under IoC where the dependencies required by an object are provided externally rather than the object creating them itself. This can be done via constructor injection, setter injection, or field injection. DI promotes loose coupling and enhances the maintainability of the application. In Spring, beans and their dependencies are defined in configuration files or annotations, and the framework automatically wires them together.
Spring Data JPA is a part of the larger Spring Data project that simplifies database access and provides a consistent programming model. It leverages Java Persistence API (JPA) to interact with relational databases, and it aims to significantly reduce the amount of boilerplate code required to implement data access layers.
Its advantages include simplifying CRUD operations, providing powerful query capabilities via method names and an easy-to-use query language, and offering seamless integration with Spring's dependency injection and transaction management. It also helps in implementing custom repositories and reducing development time, making the data access layer more maintainable and readable.
Spring AOP is a programming paradigm that allows you to separate cross-cutting concerns, like logging or security, from the main business logic of your application. This helps in keeping the code cleaner and more modular. You can use it to define aspects, which are modules that encapsulate behaviors affecting multiple classes, like logging across different services.
To use it, you typically define aspects using annotations like @Aspect and advice types such as @Before, @After, and @Around to hook into specific join points in your code execution. For example, you can add a logging aspect that logs method execution times by creating an aspect class and annotating a method with @Around, then specifying a pointcut expression to match the methods you want to intercept.
Java-based configuration in Spring is done by creating a class annotated with @Configuration
. Within this class, you define your beans using @Bean
methods. This allows you to manage your beans and their dependencies in a type-safe and refactor-friendly way. Here's an example:
```java @Configuration public class AppConfig {
@Bean
public MyService myService() {
return new MyServiceImpl();
}
@Bean
public MyRepository myRepository() {
return new MyRepositoryImpl();
}
} ```
Then, you can bootstrap the Spring context using AnnotationConfigApplicationContext
:
java
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
MyService myService = context.getBean(MyService.class);
This way, you avoid the XML configuration files and keep everything within your Java code, making it easier to navigate and manage.
In Spring, the main types of dependency injection are constructor-based, setter-based, and field-based injection. Constructor-based injection involves passing dependencies as parameters to a class constructor, which helps in creating immutable objects and ensures that mandatory dependencies are always available. Setter-based injection, on the other hand, uses setter methods to inject dependencies into a class, making it optional and more flexible. Field-based injection directly injects dependencies into fields using annotations like @Autowired
, which can be convenient but might make unit testing harder.
Spring supports RESTful web services mainly through its Spring MVC framework. With Spring MVC, you can easily map HTTP requests to controllers using annotations like @RestController
and @RequestMapping
. For instance, you can use @GetMapping
for HTTP GET requests, @PostMapping
for POST requests, and so on, which makes the code both intuitive and easy to maintain.
Spring also offers powerful features for handling JSON and XML data formats using the Jackson library or similar ones, making the response transformation process seamless. Additionally, it includes support for content negotiation to return the appropriate format based on client requests, and exception handling to ensure robust and user-friendly APIs.
The @Transactional annotation in Spring is used for managing transaction boundaries. It simplifies transaction management by allowing you to define transaction settings directly on the method or class level, ensuring consistency and rollback in case of errors. This means that you don't have to write boilerplate code to start, commit, or roll back transactions; the framework takes care of it based on your configurations.
In Spring, the Singleton scope means that the container creates exactly one instance of a bean, and all requests for that bean will return the same instance. This is the default scope in Spring. On the other hand, the Prototype scope means that the container creates a new instance of the bean every time it is requested. Singleton is ideal for shared resources, whereas Prototype is suitable for stateful or per-execution configurations.
These annotations are all stereotypes in Spring, but they serve different roles.
@Component
is a generic stereotype for any Spring-managed component. It’s a general-purpose annotation used for any type of class.
@Controller
is a specialization of @Component
for classes that handle web requests. It's typically used in MVC architecture for defining controllers.
@Service
also extends @Component
and is used to denote service-layer classes. It's useful for business logic and you get the semantic clarity that the annotated class holds some business service.
@Repository
is a specialization of @Component
for data access objects (DAOs). It adds additional behaviors to DAO classes, such as automatic exception translation into Spring's DataAccessException.
Spring manages database transactions using the @Transactional annotation. It provides a declarative way to manage transaction boundaries. When you mark a method with @Transactional, Spring creates a proxy that wraps the method call and manages the transaction, committing it if the method completes successfully or rolling it back if an exception is thrown. This way, you don't have to write boilerplate code to begin, commit, or rollback transactions explicitly. Spring's transaction management is also flexible, supporting various APIs and integrating with Hibernate, JPA, and JDBC seamlessly.
Spring Beans are objects that are managed by the Spring IoC (Inversion of Control) container. Essentially, they are the backbone of a Spring application and represent various components that are instantiated, assembled, and managed within the framework.
The Bean lifecycle includes several stages: instantiation, where the Bean is created; dependency injection, where dependencies are injected into the Bean; initialization, where any initialization code defined for the Bean is executed; and finally, destruction, where the Bean is cleaned up before being removed from the container. You can hook into these lifecycle events using custom initialization and destruction methods, or by implementing special interfaces like InitializingBean
and DisposableBean
.
Both @Autowired
and @Inject
are used for dependency injection, but @Autowired
is specific to Spring, while @Inject
is part of the Java CDI (Contexts and Dependency Injection) framework. @Autowired
belongs to the Spring framework, offering additional features like setting the required parameter to true or false, which tells the container whether the dependency is mandatory. @Inject
, on the other hand, follows the standard defined by JSR-330, making your code more portable across different DI frameworks.
ApplicationContext in Spring acts as the central interface for providing configuration information to the application. It extends the BeanFactory interface, offering more advanced features such as event propagation, declarative mechanisms to create a bean, and several types of specific application contexts like WebApplicationContext for web applications. Essentially, it’s used to manage the entire lifecycle of your beans, handle dependency injection, and provide more functionality like internationalization and application event handling.
In Spring MVC, exceptions can be handled using @ExceptionHandler
in a controller, @ControllerAdvice
for global exception handling across controllers, or by configuring HandlerExceptionResolver
. @ExceptionHandler
lets you define a method to handle exceptions thrown by a specific controller. @ControllerAdvice
brings a global aspect by allowing you to handle exceptions across multiple controllers. For even more centralized handling, you could implement a HandlerExceptionResolver
as a bean, which provides a more programmatic approach to handling exceptions.
Using @ExceptionHandler
is as simple as annotating a method within your controller with @ExceptionHandler
(Exception.class). This method can then return a model and view or a response entity. With @ControllerAdvice
, you annotate a class and define methods with the @ExceptionHandler
, @InitBinder
, or @ModelAttribute
annotations to apply those methods globally. For HandlerExceptionResolver
, you implement the resolveException
method to handle exceptions in a custom way.
Here’s a simple example using @ControllerAdvice
:
```java
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleGenericException(Exception ex) {
return new ResponseEntity<>("An error occurred: " + ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
} ```
The @Scope annotation in Spring is used to define the lifecycle and visibility of a Spring bean. Essentially, it tells the container how to create and manage bean instances. By default, Spring beans are singleton-scoped, meaning there's only one instance per Spring container. However, with @Scope, you can specify other scopes like prototype, which creates a new instance each time it's requested, or request and session for web applications to tie the bean's lifecycle to HTTP requests or sessions, respectively. This allows for greater flexibility in how beans are managed and utilized within an application.
Spring Profiles are a way to segregate parts of your application configuration and make it available only in certain environments. This is particularly useful for scenarios like differentiating between development, testing, and production settings. You can annotate your beans with @Profile
to specify which profile they belong to, and in your configuration files like application.properties
, you can activate a profile by using spring.profiles.active
.
For example, if you have a bean that connects to a database, you might have different profiles for dev
, test
, and prod
environments so that each one connects to a different database. When you run your application, you simply specify which profile to use, and Spring will only load the beans and settings for that profile. This helps manage environment-specific configurations efficiently.
You can configure a DataSource in Spring either by using Java-based configuration or through XML configuration. For Java-based configuration, you can use the @Bean
annotation in a @Configuration
class to create and configure an instance of DataSource
. For example, you might use HikariDataSource
for that purpose.
java
@Configuration
public class DataSourceConfig {
@Bean
public DataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setDriverClassName("com.mysql.cj.jdbc.Driver");
config.setJdbcUrl("jdbc:mysql://localhost:3306/yourdb");
config.setUsername("username");
config.setPassword("password");
return new HikariDataSource(config);
}
}
Alternatively, you can use application properties in Spring Boot to configure the DataSource, which will automatically be picked up by Spring Boot.
properties
spring.datasource.url=jdbc:mysql://localhost:3306/yourdb
spring.datasource.username=username
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
Spring Security is a powerful framework that focuses on providing both authentication and authorization to Java applications. It is highly customizable and integrates seamlessly with the Spring framework, making it easier to secure your web applications, microservices, and APIs.
To implement authentication, you typically start by configuring a SecurityConfig
class that extends WebSecurityConfigurerAdapter
. In this class, you'll override methods like configure
to set up user details, password encoding, and specify authentication mechanisms like form login, basic authentication, or OAuth2.
For authorization, you can use annotations like @PreAuthorize
and @Secured
to specify access control on methods. Additionally, within your SecurityConfig
, you can use the authorizeRequests()
method to define URL-based access restrictions, indicating which roles or user authorities are permitted to access specific endpoints.
You can implement caching in a Spring application by using Spring's caching abstraction. First, you'll need to add the necessary dependencies like Spring Cache and a caching provider, such as EhCache, Redis, or even a simple in-memory cache like ConcurrentMapCache. Then you can enable caching in your configuration class by adding the @EnableCaching
annotation. Finally, use @Cacheable
on methods where you want to cache the result, specifying a cache name. For example:
```java @EnableCaching @Configuration public class CacheConfig { // Configure your cache manager here if needed }
@Service public class MyService { @Cacheable("myCache") public MyData getData(String id) { // Method logic } } ```
This way, the first time the getData
method is called with a given id
, the result is cached. Subsequent calls with the same id
will return the cached result.
The @EnableAutoConfiguration annotation in Spring Boot is used to enable auto-configuration, which automatically configures your Spring application based on the dependencies you have added. It looks at the libraries on the classpath and automatically applies the appropriate configuration without you having to specify it manually. This greatly simplifies setup and reduces boilerplate code, making it quicker to get a Spring application up and running.
A Spring Boot starter is a pre-configured set of dependencies and templates that help you quickly set up and start working on various aspects of a Spring Boot application. These starters are designed to reduce the amount of boilerplate code and configuration you need to write. For example, if you want to create a web application, you can include the spring-boot-starter-web
starter in your project dependencies, and it will automatically bring in everything you need to get a simple web app up and running.
To use a starter, you just include it in your build configuration. If you're using Maven, you would add a dependency in your pom.xml
file, like so:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
If you're using Gradle, you would add it to your build.gradle
file:
groovy
implementation 'org.springframework.boot:spring-boot-starter-web'
After doing this, Spring Boot automatically sets up the necessary configurations and dependencies, so you can focus on writing your business logic.
@Controller is used to define a conventional controller that handles HTTP requests and returns a view, typically as a result of invoking a service or processing form data. If you use @Controller, you'd normally use methods that return view names, and you'd pair them with @ResponseBody or other annotations to send JSON or XML data.
@RestController is a specialization of @Controller, introduced to simplify the creation of RESTful web services. It's essentially a combination of @Controller and @ResponseBody. So, when you use @RestController, you don't need to annotate each method with @ResponseBody. This means that every method in the @RestController will return data directly in the form of JSON or XML, suitable for APIs.
Securing REST APIs in a Spring application involves a combination of authentication and authorization mechanisms. You typically use Spring Security, which provides robust and customizable security features. One common method is using OAuth2 or JWT tokens for authentication, ensuring that only authenticated users can access the endpoints.
Additionally, you can use role-based access control to ensure that authenticated users have the appropriate permissions. This is done by configuring security filters and applying annotations like @PreAuthorize to your controller methods. Enabling HTTPS to encrypt data in transit and applying CORS policies to control which domains can access your APIs further strengthens security.
Handling file uploads in Spring MVC is pretty straightforward. You start by adding the commons-fileupload
dependency to your project, which Spring uses under the hood to deal with multipart requests. In your Spring configuration, you need to enable multipart support by configuring a MultipartResolver
bean, usually CommonsMultipartResolver
.
In your controller, you can then create a method that maps to the file upload endpoint and accepts a MultipartFile
parameter. You'll use this parameter to access the uploaded file's content, which can be saved to your server or processed as needed. Annotate the controller method with @PostMapping
or @RequestMapping
depending on your preference. For example:
java
@PostMapping("/upload")
public String handleFileUpload(@RequestParam("file") MultipartFile file) {
if (!file.isEmpty()) {
try {
byte[] bytes = file.getBytes();
// Path to save the file
Path path = Paths.get("/path/to/save/directory/" + file.getOriginalFilename());
Files.write(path, bytes);
} catch (IOException e) {
e.printStackTrace();
return "uploadFailed";
}
}
return "uploadSuccess";
}
This code snippet highlights how you check if the file is not empty, convert it to bytes, and then save it to your desired location. Adjust the path and error handling to fit your actual use case.
Spring Cloud is a set of tools and frameworks designed to support creating, deploying, and managing microservices. It provides solutions to common problems faced in a microservices architecture, such as service discovery, configuration management, circuit breakers, and distributed tracing. With Spring Cloud, developers can more easily build applications that are resilient and scalable.
For example, service discovery allows microservices to find each other and communicate effectively without hard-coding network locations. Configuration management simplifies using a central place to manage settings that might change between environments. Additionally, features like circuit breakers can make your system more fault-tolerant by handling service failures gracefully. These tools collectively enable faster development cycles and more maintainable, reliable systems.
Testing Spring applications typically involves using a combination of unit tests and integration tests. For unit tests, you can use frameworks like JUnit or TestNG to test individual components in isolation, often utilizing mocks created with Mockito to simulate dependencies.
For integration tests, Spring provides the @SpringBootTest
annotation, which can load the full application context and let you test how components interact with one another. Additionally, tools like Spring Boot's TestRestTemplate
can help test HTTP requests and responses in a more realistic environment.
You can configure property sources in Spring in a few straightforward ways. One common method is using the @PropertySource
annotation on a configuration class to load properties from a file. You can also specify multiple property sources by chaining multiple @PropertySource
annotations.
Another way is through the application.properties
or application.yml
file in a Spring Boot project. This file is automatically read by Spring Boot and loaded into the application context. You can also programmatically manipulate property sources using the Environment
and PropertySourcesPlaceholderConfigurer
classes if you need more complex configurations.
The @Async
annotation in Spring is used to mark methods that should run asynchronously. When you annotate a method with @Async
, Spring will execute that method in a separate thread, thereby allowing the caller to continue processing without waiting for the method's completion. This is particularly useful for tasks that are time-consuming or can be performed independently of the main flow, like sending emails, processing large files, or calling external APIs. Just remember to enable async support in your Spring configuration with @EnableAsync
.
Spring Framework offers several advantages, such as simplifying Java development with its comprehensive infrastructure support. Its dependency injection (DI) feature reduces the need for manually writing complex dependencies between objects, making the code more modular and easier to test and maintain.
Additionally, Spring provides robust AOP (Aspect-Oriented Programming) capabilities that help separate cross-cutting concerns like logging, transaction management, and security from business logic. This makes the code cleaner and more focused. The ecosystem also includes various projects like Spring Boot, Spring Security, and Spring Data, which accelerate development by providing solutions to common problems and improving productivity.
The @Qualifier annotation is used in Spring to resolve the ambiguity that arises when multiple beans of the same type are available for dependency injection. It gives a more specific identifier to a bean, so Spring can know exactly which one to inject.
To use @Qualifier, you annotate a field, constructor, or method parameter with it and specify the name of the bean you want to inject. For example:
java
@Autowired
@Qualifier("specificBeanName")
private SomeService someService;
Here, @Qualifier("specificBeanName") tells Spring to inject the bean named "specificBeanName" into someService.
Spring Event Handling is a mechanism for loosely coupled communication between different components in a Spring application. Essentially, it allows a component to publish an event that other components can listen for and react to. You can create custom events by extending the ApplicationEvent
class and then publish them using the ApplicationEventPublisher
. Other components, marked with the @EventListener
annotation, can handle these events when they're emitted. This is particularly useful for decoupling the logic and promoting a clean, modular, and maintainable codebase.
To implement pagination and sorting in Spring Data JPA, you typically use the Pageable
interface. You can pass a Pageable
instance to repository methods, which allows you to handle both pagination and sorting. For example, you can create a PageRequest
using PageRequest.of(page, size, Sort.by("fieldName"))
and pass it to your repository method like findAll(Pageable pageable)
. This will give you a Page
object that contains the data for the requested page, as well as metadata like the total number of pages.
For example, if you have an entity called Person
and a repository for it, you could do something like this:
java
Pageable pageable = PageRequest.of(0, 10, Sort.by("lastName"));
Page<Person> page = personRepository.findAll(pageable);
This will retrieve the first 10 Person
entities sorted by the lastName
. You can then use page.getContent()
to get the list of Person
objects on that page.
DispatcherServlet is the front controller in Spring MVC that manages all HTTP requests and responses. It acts as a central point for handling web requests, routing them to the appropriate controllers, and rendering the correct views. When a request comes in, the DispatcherServlet consults the HandlerMapping to figure out which controller should handle it, then uses a view resolver to determine how to render the response. It simplifies the flow and processing of web requests, making the architecture more manageable and modular.
There is no better source of knowledge and motivation than having a personal mentor. Support your interview preparation with a mentor who has been there and done that. Our mentors are top professionals from the best companies in the world.
We’ve already delivered 1-on-1 mentorship to thousands of students, professionals, managers and executives. Even better, they’ve left an average rating of 4.9 out of 5 for our mentors.
"Naz is an amazing person and a wonderful mentor. She is supportive and knowledgeable with extensive practical experience. Having been a manager at Netflix, she also knows a ton about working with teams at scale. Highly recommended."
"Brandon has been supporting me with a software engineering job hunt and has provided amazing value with his industry knowledge, tips unique to my situation and support as I prepared for my interviews and applications."
"Sandrina helped me improve as an engineer. Looking back, I took a huge step, beyond my expectations."
"Andrii is the best mentor I have ever met. He explains things clearly and helps to solve almost any problem. He taught me so many things about the world of Java in so a short period of time!"
"Greg is literally helping me achieve my dreams. I had very little idea of what I was doing – Greg was the missing piece that offered me down to earth guidance in business."
"Anna really helped me a lot. Her mentoring was very structured, she could answer all my questions and inspired me a lot. I can already see that this has made me even more successful with my agency."