- What is the Spring Framework ? and advantages of Spring Framework ?
- List out major features of Spring Framework
- Which are the Spring Framework modules ?
- How do you provide configuration metadata to the Spring Container?
- What is Inversion of Control (IoC) in Spring?
- What is Dependency Injection (DI) in Spring?
- What are Spring Beans?
- Explain the different types of Dependency Injection in Spring
- What is the difference between BeanFactory and ApplicationContext?
- What are the scopes of a Spring Bean?
- What is Spring AOP?
- What is Spring MVC?
- What is Spring Boot?
- Spring vs Spring Boot
- Spring Boot vs Spring MVC
=> Spring is a light weight framework. It can be called as framework of frameworks
=> It provides support to various frameworks such as Hibernate, JSF, EJB
=> Java Spring Framework is a popular, open source, enterprise-level framework for creating standalone, production grade applications that run on JVM
Advantages of Spring Framework :
=> Loose coupling : Spring applications are loosely coupled using the concept called Dependency Injection (DI)
=> Predefined templates : Spring Framework provides templates for Hibernate, JDBC, JPA, etc technologies. Spring Framework can handle basic steps of these technologies. So, there is no need to code much.
For example, In case JDBC template, we don’t need to write commits, exception handling, creating and closing connections
02. Modular architecture :
=> Organized into modules (eg. Spring Core, Spring MVC, Spring Security) that can be used independently
=> Allow developers to include only the required components, reducing complexity
03. Spring MVC (web framework) :
=> Provides a Model-View-Controller framework for building web applications and RESTful APIs
04. Aspect Oriented Programming (AOP) :
=> Enables separation of cross-cutting concerns (eg. logging, security, transaction management)
05. Transaction Management :
=> Simplifies transaction handling with declarative (eg. @Transactional) or programmatic approaches
06. Data Access and Integration :
=> Simplifies database operations with Spring DAO and ORM modules
=> Integrates with JDBC, Hibernate, JPA and NoSQL databases (via Spring Data)
07. Spring Security :
=> Offers robust authentication and authorization mechanisms
08. Spring Boot (Simplified development)
09. Messaging Support :
=> Offers integration with messaging systems like JMS, RabbitMQ and Kafka
10. Internationalization :
=> Provides support for building multilingual applications with message source abstractions.
11. Spring Batch :
=> Supports job scheduling, retry, and transaction management
12. RestClient support :
=> Simplifies HTTP client operations with RestTemplate
13. Extensibility :
=> Supports integration with cloud platforms (e.g., Spring Cloud for microservices)
The Spring Framework is organized into a modular architecture, allowing developers to use only the components they need
1. Core Container
Spring Core: Provides the fundamental functionality of the Inversion of Control (IoC) container and Dependency Injection (DI). It manages bean creation, configuration, and lifecycle.
Spring Beans: Handles the management of Java beans within the IoC container, including their configuration and dependency injection.
Spring Context: Extends the Core and Beans modules by adding features like internationalization (i18n), event propagation, resource loading, and application context management.
Spring Expression Language (SpEL): Enables dynamic querying and manipulation of object graphs at runtime, used in bean definitions and configurations.
2. Data Access/Integration
Spring JDBC: Simplifies database access using JDBC by providing a higher-level abstraction, reducing boilerplate code and handling exceptions consistently.
Spring ORM: Integrates with Object-Relational Mapping tools like Hibernate, JPA, and MyBatis, simplifying database operations.
Spring Data: Provides a consistent data access layer for both SQL and NoSQL databases, with repository abstractions for rapid development.
Spring TX (Transaction Management): Offers declarative and programmatic transaction management for database and other resource operations.
Spring JMS: Simplifies messaging with Java Message Service (JMS), supporting asynchronous communication with message brokers like ActiveMQ or RabbitMQ.
3. Web
Spring MVC: A Model-View-Controller framework for building web applications and RESTful APIs, with support for annotations like @Controller and @RestController.
Spring WebFlux: A reactive web framework for building non-blocking, asynchronous web applications, compatible with reactive streams.
Spring Web Services: Facilitates the creation and consumption of SOAP-based and RESTful web services.
4. Aspect-Oriented Programming (AOP)
Spring AOP: Enables aspect-oriented programming to handle cross-cutting concerns (e.g., logging, security) by separating them from business logic.
Spring Aspects: Provides integration with AspectJ for advanced AOP capabilities.
5. Security
Spring Security: Offers comprehensive authentication, authorization, and protection against common security vulnerabilities (e.g., CSRF, XSS). Supports OAuth2, JWT, and role-based access control.
6. Messaging
Spring Messaging: Provides abstractions for messaging protocols (e.g., STOMP, WebSocket) and integration with message brokers like RabbitMQ and Kafka.
7. Testing
Spring Test: Supports unit and integration testing with tools like JUnit and TestNG, including mock objects and Spring-specific testing features like TestContext Framework.
8. Integration
Spring Integration: Implements enterprise integration patterns for connecting with external systems via messaging, file transfer, or other protocols.
Spring Batch: Provides a framework for processing large volumes of data in batch jobs, with features like retry, skip, and transaction management.
9. Instrumentation
Spring Instrument: Supports class loading and instrumentation, often used for advanced monitoring or profiling in specific environments.
10. Spring Boot (Extension, not a core module)
While technically a separate project, Spring Boot builds on the Spring Framework by providing auto-configuration, embedded servers, and simplified dependency management. It leverages many of the above modules to streamline application development.
=> Java based configuration
=> Annotation based configuration
=> Mixed configuration (Combining XML, Java based and annotation based)
=> Spring Boot Auto Configuration
What is Inversion of Control (IoC) in Spring?
Traditional Control vs Inversion of Control :
Traditional Control: In traditional programming, a class is responsible for creating and managing its dependencies. For example, a class might instantiate another object directly using the new keyword, tightly coupling the two classes.
Inversion of Control: IoC inverts this responsibility. Instead of a class creating its dependencies, the Spring IoC Container creates, configures, and injects dependencies into the class at runtime. This reduces tight coupling and makes the code more flexible and testable.
Dependency Injection (DI) is used to achieve IOC in Spring.
Spring IOC container performs the following key functions :
=> Instantiates and manages objects (beans) defined in configuration meta data (XML, Java Based or Annotation)
=> Dependency Injection (DI) : Injects dependencies into beans via constructor injection/setter injection/field injection
=> Manages entire life cycle of beans from creation to destruction
Two main implementation of IOC container are :
=> BeanFactory
=> ApplicationContext
Benefits of IOC in Spring :
=> Loose Coupling
=> Configuration can be changed without modifying the code (eg. via XML or properties file)
=> Dependencies can be mocked for unit testing
=> IOC takes care of beans clean up as well
Example: IoC with Dependency Injection in Spring
1. Define Beans
import org.springframework.stereotype.Service;
@Service
class MyService {
public String getMessage() {
return "Hello from MyService!";
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
class MyController {
private final MyService service;
// Constructor Injection
@Autowired
public MyController(MyService service) {
this.service = service;
}
public String getServiceMessage() {
return service.getMessage();
}
}
2. Configuration Class
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = "com.example") // Scans for @Component, @Service, etc.
public class AppConfig {
}
3. Main Application
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
// Initialize the Spring IoC Container
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// Retrieve bean from the container
MyController controller = context.getBean(MyController.class);
System.out.println(controller.getServiceMessage()); // Output: Hello from MyService!
}
}
How IoC Works in This Example
=> The Spring IoC Container (via ApplicationContext) scans for @Component and @Service annotations due to @ComponentScan.
=> It creates instances of MyService and MyController as beans.
=> The container injects MyService into MyController via constructor injection (using @Autowired).
=> The application retrieves the MyController bean from the container, which already has its dependency (MyService) wired.
IoC in Different Configuration Types
XML-Based:
xml<bean id="myService" class="com.example.MyService" />
<bean id="myController" class="com.example.MyController">
<constructor-arg ref="myService" />
</bean>
Java-Based:
java@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyService();
}
@Bean
public MyController myController() {
return new MyController(myService());
}
}
The container processes @Bean methods to create and wire beans.
Annotation-Based: As shown in the example above, using @Component, @Service, and @Autowired with component scanning.
Key points :
Bean Scopes: IoC supports various scopes (e.g., singleton, prototype) to control bean instantiation. Default is singleton.
Lazy vs. Eager Initialization: Beans are eagerly initialized by default in ApplicationContext, but you can use @Lazy for lazy initialization.
=> Dependency Injection (DI) is used to achieve Inversion Of Control (IOC) in Spring
Types of Dependency Injection in Spring :
1. Constructor Injection
2. Setter Injection
3. Field Injection
1. Constructor Injection
=> Dependencies are provided via a constructor, ensuring the object is fully initialized with its dependencies.
=> Cons: Can lead to verbose constructors if many dependencies are required. (verbose means expressed in more words than required)
=> Example (Annotation Based) :
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;
@Component
class MyService {
public String getMessage() {
return "Hello from MyService!";
}
}
@Component
class MyController {
private final MyService service;
@Autowired // Injects MyService via constructor
public MyController(MyService service) {
this.service = service;
}
public String getServiceMessage() {
return service.getMessage();
}
}
2. Setter Injection
=> Dependencies are injected via setter methods, allowing optional dependencies or runtime changes.
Example (Annotation-based):
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;
@Component
class MyService {
public String getMessage() {
return "Hello from MyService!";
}
}
@Component
class MyController {
private MyService service;
@Autowired // Injects MyService via setter
public void setService(MyService service) {
this.service = service;
}
public String getServiceMessage() {
return service.getMessage();
}
}
3. Field Injection
=> Dependencies are injected directly into fields using annotations like @Autowired.
=> Pros: Concise and requires minimal code.
=> Cons: Harder to test (cannot easily mock dependencies), less explicit, and breaks encapsulation.
=> Example :
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;
@Component
class MyService {
public String getMessage() {
return "Hello from MyService!";
}
}
@Component
class MyController {
@Autowired // Injects directly into the field
private MyService service;
public String getServiceMessage() {
return service.getMessage();
}
}
Configuration to Enable DI :
To make the above examples work, you need to enable component scanning (for annotation-based DI):
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = "com.example") // Scans for @Component, @Service, etc.
public class AppConfig {
}
Main Application:
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
MyController controller = context.getBean(MyController.class);
System.out.println(controller.getServiceMessage()); // Output: Hello from MyService!
}
}
Key Points :
Preferred Injection Type: Constructor injection is recommended for mandatory dependencies due to immutability and explicitness. Setter injection is useful for optional dependencies, while field injection is generally discouraged in production code.
Autowiring: The @Autowired annotation resolves dependencies by type, but you can use @Qualifier or @Resource to resolve ambiguities (e.g., multiple beans of the same type).
Spring Boot: Simplifies DI with auto-configuration and @SpringBootApplication, which enables component scanning by default.
Circular Dependencies: DI can lead to circular dependency issues, which Spring can sometimes resolve for setter injection but may require @Lazy or redesign for constructor injection.
Bean Scopes: DI works with different bean scopes (e.g., singleton, prototype), affecting how dependencies are injected.
Practical Example with Spring Boot
Since Spring Boot is common in modern Java projects, here’s a quick example combining DI with Spring Boot:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication // Enables auto-configuration and component scanning
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Service
class MyService {
public String getMessage() {
return "Hello from Spring Boot DI!";
}
}
@RestController
class MyController {
private final MyService service;
public MyController(MyService service) { // Constructor Injection
this.service = service;
}
@GetMapping("/message")
public String getMessage() {
return service.getMessage();
}
}
Access: Run the application and visit http://localhost:8080/message to see the output.
What are Spring Beans?
Explain the different types of Dependency Injection in Spring
Types of Dependency Injection in Spring :
1. Constructor Injection
2. Setter Injection
3. Field Injection
1. Constructor Injection
=> Dependencies are provided via a constructor, ensuring the object is fully initialized with its dependencies.
=> Cons: Can lead to verbose constructors if many dependencies are required. (verbose means expressed in more words than required)
=> Example (Annotation Based) :
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;
@Component
class MyService {
public String getMessage() {
return "Hello from MyService!";
}
}
@Component
class MyController {
private final MyService service;
@Autowired // Injects MyService via constructor
public MyController(MyService service) {
this.service = service;
}
public String getServiceMessage() {
return service.getMessage();
}
}
2. Setter Injection
=> Dependencies are injected via setter methods, allowing optional dependencies or runtime changes.
Example (Annotation-based):
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;
@Component
class MyService {
public String getMessage() {
return "Hello from MyService!";
}
}
@Component
class MyController {
private MyService service;
@Autowired // Injects MyService via setter
public void setService(MyService service) {
this.service = service;
}
public String getServiceMessage() {
return service.getMessage();
}
}
3. Field Injection
=> Dependencies are injected directly into fields using annotations like @Autowired.
=> Pros: Concise and requires minimal code.
=> Cons: Harder to test (cannot easily mock dependencies), less explicit, and breaks encapsulation.
=> Example :
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;
@Component
class MyService {
public String getMessage() {
return "Hello from MyService!";
}
}
@Component
class MyController {
@Autowired // Injects directly into the field
private MyService service;
public String getServiceMessage() {
return service.getMessage();
}
}
Configuration to Enable DI :
To make the above examples work, you need to enable component scanning (for annotation-based DI):
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = "com.example") // Scans for @Component, @Service, etc.
public class AppConfig {
}
Main Application:
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
MyController controller = context.getBean(MyController.class);
System.out.println(controller.getServiceMessage()); // Output: Hello from MyService!
}
}
Key Points :
Preferred Injection Type: Constructor injection is recommended for mandatory dependencies due to immutability and explicitness. Setter injection is useful for optional dependencies, while field injection is generally discouraged in production code.
Autowiring: The @Autowired annotation resolves dependencies by type, but you can use @Qualifier or @Resource to resolve ambiguities (e.g., multiple beans of the same type).
Spring Boot: Simplifies DI with auto-configuration and @SpringBootApplication, which enables component scanning by default.
Circular Dependencies: DI can lead to circular dependency issues, which Spring can sometimes resolve for setter injection but may require @Lazy or redesign for constructor injection.
Bean Scopes: DI works with different bean scopes (e.g., singleton, prototype), affecting how dependencies are injected.
Practical Example with Spring Boot
Since Spring Boot is common in modern Java projects, here’s a quick example combining DI with Spring Boot:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication // Enables auto-configuration and component scanning
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Service
class MyService {
public String getMessage() {
return "Hello from Spring Boot DI!";
}
}
@RestController
class MyController {
private final MyService service;
public MyController(MyService service) { // Constructor Injection
this.service = service;
}
@GetMapping("/message")
public String getMessage() {
return service.getMessage();
}
}
Access: Run the application and visit http://localhost:8080/message to see the output.
What is the difference between BeanFactory and ApplicationContext?
=> Spring Boot exclusively uses ApplicationContext (via SpringApplication.run()), making BeanFactory irrelevant in most modern applications.
Example with Spring Boot:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(Application.class, args);
MyService service = context.getBean(MyService.class);
System.out.println(service.getMessage());
}
}
What are the scopes of a Spring Bean?
Beans have scopes that define their lifecycle and visibility. The default is singleton. Common scopes include:
Singleton: One instance per container (default, suitable for stateless services).
Prototype: New instance each time requested (for stateful objects).
Request: One instance per HTTP request (web apps).
Session: One instance per HTTP session.
Application: One instance per ServletContext (web apps).
WebSocket: One instance per WebSocket session.
1. Singleton (Default) :
=> One instance per container (default, suitable for stateless services).
=> Created during container initialization (in ApplicationContext) or on first request (in BeanFactory), and destroyed when the container shuts down.
=> Suitable for stateless beans, such as services, repositories, or configuration objects, where a single instance is sufficient.
=> Example
import org.springframework.stereotype.Component;
@Component
public class MyService {
public String getMessage() {
return "Singleton Bean: " + this.hashCode(); // Same hashCode for all calls
}
}
Output: All calls to context.getBean(MyService.class) return the same instance (same hashCode).
2. Prototype
=> A new instance of the bean is created each time it is requested (via getBean() or dependency injection).
=> Created on demand; Spring does not manage the destruction of prototype beans (application must handle cleanup).
=> Suitable for stateful beans or cases where a new instance is needed for each operation (e.g., temporary objects or request-specific data holders).
=> Example :
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("prototype")
public class MyPrototypeBean {
public String getMessage() {
return "Prototype Bean: " + this.hashCode(); // Different hashCode each time
}
}
Output: Each call to context.getBean(MyPrototypeBean.class) returns a new instance (different hashCode).
3. Request
=> A new instance of the bean is created for each HTTP request in a web-aware Spring application (e.g., Spring MVC or Spring Boot).
=> Tied to the lifecycle of an HTTP request; created when the request starts and destroyed when it ends.
=> Tied to the lifecycle of an HTTP request; created when the request starts and destroyed when it ends.
=> Only available in a web-aware ApplicationContext (e.g., WebApplicationContext).
=> Example :
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;
@Component
@Scope(WebApplicationContext.SCOPE_REQUEST)
public class MyRequestBean {
public String getMessage() {
return "Request Bean: " + this.hashCode(); // New instance per HTTP request
}
}
4. Session
=> A single instance of the bean is created for each HTTP session in a web-aware Spring application.
=> Tied to the lifecycle of an HTTP session; created when the session starts and destroyed when it expires or is invalidated.
=> Ideal for user-specific data that persists across multiple requests within a session (e.g., user preferences or authentication data).
=> Only available in a web-aware ApplicationContext.
=> Example :
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;
@Component
@Scope(WebApplicationContext.SCOPE_SESSION)
public class MySessionBean {
public String getMessage() {
return "Session Bean: " + this.hashCode(); // Same instance within a session
}
}
5. Application
=> A single instance of the bean is created for the entire ServletContext in a web-aware Spring application.
=> Tied to the lifecycle of the ServletContext; created when the web application starts and destroyed when it shuts down.
=> Suitable for application-wide resources shared across all users and sessions (e.g., global configuration or caches).
=> Only available in a web-aware ApplicationContext.
=> Example :
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;
@Component
@Scope(WebApplicationContext.SCOPE_APPLICATION)
public class MyApplicationBean {
public String getMessage() {
return "Application Bean: " + this.hashCode(); // Same instance for entire app
}
}
6. WebSocket
=> A single instance of the bean is created for each WebSocket session in a Spring application using WebSocket support (introduced in Spring 4.0).
=> Tied to the lifecycle of a WebSocket session; created when the session starts and destroyed when it ends.
=> Useful for WebSocket-based applications where data is specific to a WebSocket connection (e.g., real-time chat or notifications).
=> Requires Spring’s WebSocket support (e.g., via spring-websocket).
=> Example :
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("websocket")
public class MyWebSocketBean {
public String getMessage() {
return "WebSocket Bean: " + this.hashCode(); // Same instance per WebSocket session
}
}
Key points :
=> Singleton is the default unless explicitly specified. Be cautious when assuming singleton behavior for stateful beans.
=> Spring does not manage the destruction of prototype beans, so memory leaks are possible if not handled properly (e.g., holding references).
=> Web-Aware Scopes: request, session, application, and websocket require a web-aware ApplicationContext (e.g., WebApplicationContext). They throw errors in non-web contexts.
=> Spring Boot simplifies scope usage with @Scope annotations and auto-configuration, but web-aware scopes require spring-web dependencies.
=> Singleton beans are shared across threads, so ensure thread-safety for stateful singletons (e.g., avoid mutable fields).
What is Spring AOP?
=> Spring AOP (Aspect-Oriented Programming) is a module in the Spring Framework that enables modularizing cross-cutting concerns (e.g., logging, security, transaction management) separate from business logic
=> It uses aspects to apply reusable logic (advice) to specific points (join points) in the code, defined via annotations, XML, or AspectJ
=> Example :
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.MyService.*(..))")
public void logBefore() {
System.out.println("Method called!");
}
}
What is Spring MVC?
What is Spring Boot?
Spring vs Spring Boot
Spring | Spring Boot |
|---|---|
Spring Framework is a widely used Java EE framework for building applications.
| Spring Boot Framework is widely used to develop REST APIs.
|
It aims to simplify Java EE development that makes developers more productive.
| It aims to shorten the code length and provide the easiest way to develop Web Applications.
|
The primary feature of the Spring Framework is dependency injection.
| The primary feature of Spring Boot is Autoconfiguration. It automatically configures the classes based on the requirement.
|
It helps to make things simpler by allowing us to develop loosely coupled applications. | It helps to create a stand-alone application with less configuration. |
The developer writes a lot of code (boilerplate code) to do the minimal task. | It reduces boilerplate code. |
To test the Spring project, we need to set up the sever explicitly. | Spring Boot offers embedded server such as Jetty and Tomcat, etc. |
It does not provide support for an in-memory database. | It offers several plugins for working with an embedded and in-memory database such as H2. |
Developers manually define dependencies for the Spring project in pom.xml. | Spring Boot comes with the concept of starter in pom.xml file that internally takes care of downloading the dependencies JARs based on Spring Boot Requirement. |
Spring Boot vs Spring MVC
Spring Boot | Spring MVC |
|---|---|
Spring Boot is a module of Spring for packaging the Spring-based application with sensible defaults.
| Spring MVC is a model view controller-based web framework under the Spring framework.
|
It provides default configurations to build Spring-powered framework.
| It provides ready to use features for building a web application.
|
There is no need to build configuration manually.
| It requires build configuration manually.
|
There is no requirement for a deployment descriptor.
| A Deployment descriptor is required.
|
It avoids boilerplate code and wraps dependencies together in a single unit.
| It specifies each dependency separately.
|
It reduces development time and increases productivity.
| It takes more time to achieve the same.
|