Introduction to Spring Core
Spring Core is the fundamental module of the Spring Framework, providing the foundation for building robust and flexible Java applications. It includes essential features such as Inversion of Control (IoC) and Dependency Injection (DI), which are the backbone of the Spring Framework. These features help manage object creation and dependencies in a more maintainable and scalable way.
Key Concepts
- Inversion of Control (IoC): A design principle in which the control of object creation and management is transferred from the application code to the Spring container.
- Dependency Injection (DI): A design pattern that implements IoC by injecting dependencies into objects rather than having the objects create them directly.
Dependency Injection (DI)
Dependency Injection is a design pattern used to implement IoC, allowing the creation of dependent objects outside of a class and providing those objects to a class through various methods.
Types of DI
- Constructor Injection: Dependencies are provided through a class constructor.
- Setter Injection: Dependencies are provided through setter methods.
- Field Injection: Dependencies are provided directly into fields. (Not recommended for various reasons, such as difficulties in testing.)
Constructor Injection Example
Constructor Injection is the most preferred way of injecting dependencies in Spring. This method ensures that all mandatory dependencies are provided at the time of object creation.
Step-by-Step Example
- Create the Dependency Class
package com.example.springcore;
import org.springframework.stereotype.Component;
// This annotation marks this class as a Spring-managed component
@Component
class Dependency {
public void doSomething() {
System.out.println("Dependency doing something");
}
}
Explanation:
@Component
: This annotation marks theDependency
class as a Spring component, meaning Spring will automatically detect and create an instance of this class.
- Create the Consumer Class
package com.example.springcore;
import org.springframework.stereotype.Component;
// This annotation marks this class as a Spring-managed component
@Component
class Consumer {
private final Dependency dependency;
// Constructor injection is performed here
public Consumer(Dependency dependency) {
this.dependency = dependency;
}
public void performTask() {
dependency.doSomething();
}
}
Explanation:
@Component
: This annotation marks theConsumer
class as a Spring component.- Constructor Injection: The
Consumer
class receives theDependency
object through its constructor. This ensures that theDependency
is provided when theConsumer
is created.
- Create the Configuration Class
package com.example.springcore;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
// This annotation marks this class as a configuration class
@Configuration
// This annotation tells Spring to scan the specified package for components
@ComponentScan(basePackages = "com.example.springcore")
public class AppConfig {
}
Explanation:
@Configuration
: This annotation indicates that the class has@Bean
definition methods. Spring container can process the class to generate Spring Beans to be used in the application.@ComponentScan
: This annotation configures component scanning directives for use with@Configuration
classes. It tells Spring where to look for components (in this case, in thecom.example.springcore
package).
- Create the Main Application Class
package com.example.springcore;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class SpringCoreApplication {
public static void main(String[] args) {
// Create the application context using the AppConfig class
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// Retrieve the Consumer bean from the context
Consumer consumer = context.getBean(Consumer.class);
// Perform the task
consumer.performTask();
}
}
Explanation:
ApplicationContext
: This is the central interface to provide configuration for an application. It is used to read the configuration metadata and instantiate, configure, and assemble the objects.AnnotationConfigApplicationContext
: This is a standalone application context, accepting@Configuration
-annotated classes as input.
Setter Injection Example
Setter Injection allows dependencies to be injected through setter methods. This method is useful for optional dependencies that might not be required at object creation.
Step-by-Step Example
- Create the Dependency Class
package com.example.springcore;
import org.springframework.stereotype.Component;
// This annotation marks this class as a Spring-managed component
@Component
class Dependency {
public void doSomething() {
System.out.println("Dependency doing something");
}
}
Explanation:
@Component
: This annotation marks theDependency
class as a Spring component, meaning Spring will automatically detect and create an instance of this class.
- Create the Consumer Class
package com.example.springcore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
// This annotation marks this class as a Spring-managed component
@Component
class Consumer {
private Dependency dependency;
// Setter method for dependency injection
@Autowired
public void setDependency(Dependency dependency) {
this.dependency = dependency;
}
public void performTask() {
dependency.doSomething();
}
}
Explanation:
@Component
: This annotation marks theConsumer
class as a Spring component.@Autowired
: This annotation tells Spring to use this setter method to inject theDependency
bean into theConsumer
bean.
- Create the Configuration Class
package com.example.springcore;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
// This annotation marks this class as a configuration class
@Configuration
// This annotation tells Spring to scan the specified package for components
@ComponentScan(basePackages = "com.example.springcore")
public class AppConfig {
}
Explanation:
@Configuration
: This annotation indicates that the class has@Bean
definition methods. Spring container can process the class to generate Spring Beans to be used in the application.@ComponentScan
: This annotation configures component scanning directives for use with@Configuration
classes. It tells Spring where to look for components (in this case, in thecom.example.springcore
package).
- Create the Main Application Class
package com.example.springcore;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class SpringCoreApplication {
public static void main(String[] args) {
// Create the application context using the AppConfig class
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// Retrieve the Consumer bean from the context
Consumer consumer = context.getBean(Consumer.class);
// Perform the task
consumer.performTask();
}
}
Explanation:
ApplicationContext
: This is the central interface to provide configuration for an application. It is used to read the configuration metadata and instantiate, configure, and assemble the objects.AnnotationConfigApplicationContext
: This is a standalone application context, accepting@Configuration
-annotated classes as input.
Field Injection Example (Not Recommended)
Field Injection allows dependencies to be injected directly into fields. However, this approach is generally not recommended due to issues with immutability and difficulties in testing.
Step-by-Step Example
- Create the Dependency Class
package com.example.springcore;
import org.springframework.stereotype.Component;
// This annotation marks this class as a Spring-managed component
@Component
class Dependency {
public void doSomething() {
System.out.println("Dependency doing something");
}
}
Explanation:
@Component
: This annotation marks theDependency
class as a Spring component, meaning Spring will automatically detect and create an instance of this class.
- Create the Consumer Class
package com.example.springcore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
// This annotation marks this class as a Spring-managed component
@Component
class Consumer {
// Field injection for the dependency
@Autowired
private Dependency dependency;
public void performTask() {
dependency.doSomething();
}
}
Explanation:
@Component
: This annotation marks theConsumer
class as a Spring component.@Autowired
: This annotation tells Spring to inject theDependency
bean directly into theConsumer
bean field.
- Create the Configuration Class
package com.example.springcore;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
// This annotation marks this class as a configuration class
@Configuration
// This annotation tells Spring to scan the specified package for components
@ComponentScan(basePackages = "com.example.springcore")
public class AppConfig {
}
Explanation:
@Configuration
: This annotation indicates that the class has@Bean
definition methods. Spring container can process the class to generate Spring Beans to be used in the application.@ComponentScan
: This annotation configures component scanning directives for use with@Configuration
classes. It tells Spring where to look for components (in this case, in thecom.example.springcore
package).
- Create the Main Application Class
package com.example.springcore;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class SpringCoreApplication {
public static void main(String[] args) {
// Create the application context using the AppConfig class
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// Retrieve the Consumer bean from the context
Consumer consumer = context.getBean(Consumer.class);
// Perform the task
consumer.performTask();
}
}
Explanation:
AnnotationConfigApplicationContext
: This is the central interface to provide configuration for an application. It is used to read the configuration metadata and instantiate, configure, and assemble the objects.AnnotationConfigApplicationContext
: This is a standalone application context, accepting@Configuration
-annotated classes as input.
Inversion of Control (IoC)
IoC is a design principle in which the control of object creation and management is transferred to a container or framework. In Spring, the IoC container is responsible for managing the lifecycle and configuration of application objects.
How IoC Works
- Configuration: Define beans and their dependencies in a configuration file or class.
- Container Initialization: The Spring container reads the configuration and initializes the beans.
- Dependency Injection: The container injects dependencies into the beans based on the configuration.
- Usage: Application code retrieves the beans from the container and uses them.
IoC Example
- Create the Dependency Class
package com.example.springcore; public class Dependency { public void doSomething() { System.out.println("Dependency doing something"); } }
Explanation: This class defines a simple
Dependency
class with a methoddoSomething
.- Create the Consumer Class
package com.example.springcore; public class Consumer { private Dependency dependency; // Constructor injection is performed here public Consumer(Dependency dependency) { this.dependency = dependency; } public void performTask() { dependency.doSomething(); } }
Explanation:
- This class defines a
Consumer
class with aDependency
object. - The
Consumer
class receives theDependency
object through its constructor, ensuring that theDependency
is provided when theConsumer
is created.
- Create the Configuration Class
package com.example.springcore; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; // This annotation marks this class as a configuration class @Configuration public class AppConfig { // Define the Dependency bean @Bean public Dependency dependency() { return new Dependency(); } // Define the Consumer bean and inject the Dependency bean @Bean public Consumer consumer() { return new Consumer(dependency()); } }
Explanation:
@Configuration
: This annotation indicates that the class has@Bean
definition methods. Spring container can process the class to generate Spring Beans to be used in the application.@Bean
: This annotation tells Spring that a method annotated with@Bean
will return an object that should be registered as a bean in the Spring application context.
- Create the Main Application Class
package com.example.springcore; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class SpringCoreApplication { public static void main(String[] args) { // Create the application context using the AppConfig class ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); // Retrieve the Consumer bean from the context Consumer consumer = context.getBean(Consumer.class); // Perform the task consumer.performTask(); } }
Explanation:
ApplicationContext
: This is the central interface to provide configuration for an application. It is used to read the configuration metadata and instantiate, configure, and assemble the objects.AnnotationConfigApplicationContext
: This is a standalone application context, accepting@Configuration
-annotated classes as input.
Spring Annotation-Based Configuration
Spring allows configuration using annotations, making the code more readable and reducing the need for XML configuration files.
Example
- Create the Dependency Class
package com.example.springcore; import org.springframework.stereotype.Component; // This annotation marks this class as a Spring-managed component @Component class Dependency { public void doSomething() { System.out.println("Dependency doing something"); } }
Explanation:
@Component
: This annotation marks theDependency
class as a Spring component, meaning Spring will automatically detect and create an instance of this class.
- Create the Consumer Class
package com.example.springcore; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; // This annotation marks this class as a Spring-managed component @Component class Consumer { private final Dependency dependency; // Constructor injection is performed here @Autowired public Consumer(Dependency dependency) { this.dependency = dependency; } public void performTask() { dependency.doSomething(); } }
Explanation:
@Component
: This annotation marks theConsumer
class as a Spring component.@Autowired
(Optional): This annotation tells Spring to use the constructor to inject theDependency
bean into theConsumer
bean. Since there’s only one constructor, Spring can infer the dependency injection without this annotation.
- Create the Configuration Class
package com.example.springcore; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; // This annotation marks this class as a configuration class @Configuration // This annotation tells Spring to scan the specified package for components @ComponentScan(basePackages = "com.example.springcore") public class AppConfig { }
Explanation:
@Configuration
: This annotation indicates that the class has@Bean
definition methods. Spring container can process the class to generate Spring Beans to be used in the application.@ComponentScan
: This annotation configures component scanning directives for use with@Configuration
classes. It tells Spring where to look for components (in this case, in thecom.example.springcore
package).
- Create the Main Application Class
package com.example.springcore; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class SpringCoreApplication { public static void main(String[] args) { // Create the application context using the AppConfig class ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); // Retrieve the Consumer bean from the context Consumer consumer = context.getBean(Consumer.class); // Perform the task consumer.performTask(); } }
Explanation:
ApplicationContext
: This is the central interface to provide configuration for an application. It is used to read the configuration metadata and instantiate, configure, and assemble the objects.AnnotationConfigApplicationContext
: This is a standalone application context, accepting@Configuration
-annotated classes as input.
Spring Java-Based Configuration
Spring Java-based configuration provides a type-safe way of configuring Spring beans using Java classes.
Example
- Create the Dependency Class
package com.example.springcore; public class Dependency { public void doSomething() { System.out.println("Dependency doing something"); } }
Explanation: This class defines a simple
Dependency
class with a methoddoSomething
.- Create the Consumer Class
package com.example.springcore; public class Consumer { private Dependency dependency; // Constructor injection is performed here public Consumer(Dependency dependency) { this.dependency = dependency; } public void performTask() { dependency.doSomething(); } }
Explanation:
- This class defines a
Consumer
class with aDependency
object. - The
Consumer
class receives theDependency
object through its constructor, ensuring that theDependency
is provided when theConsumer
is created.
- Create the Configuration Class
package com.example.springcore; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; // This annotation marks this class as a configuration class @Configuration public class AppConfig { // Define the Dependency bean @Bean public Dependency dependency() { return new Dependency(); } // Define the Consumer bean and inject the Dependency bean @Bean public Consumer consumer() { return new Consumer(dependency()); } }
Explanation:
@Configuration
: This annotation indicates that the class has@Bean
definition methods. Spring container can process the class to generate Spring Beans to be used in the application.@Bean
: This annotation tells Spring that a method annotated with@Bean
will return an object that should be registered as a bean in the Spring application context.
- Create the Main Application Class
package com.example.springcore; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class SpringCoreApplication { public static void main(String[] args) { // Create the application context using the AppConfig class ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); // Retrieve the Consumer bean from the context Consumer consumer = context.getBean(Consumer.class); // Perform the task consumer.performTask(); } }
Explanation:
ApplicationContext
: This is the central interface to provide configuration for an application. It is used to read the configuration metadata and instantiate, configure, and assemble the objects.AnnotationConfigApplicationContext
: This is a standalone application context, accepting@Configuration
-annotated classes as input.
Spring Core Annotations
- @Component: Indicates that a class is a Spring component.
- @Autowired: Marks a constructor, field, or setter method to be autowired by Spring’s dependency injection.
- @Configuration: Indicates that a class declares one or more
@Bean
methods. - @Bean: Indicates that a method produces a bean to be managed by the Spring container.
- @ComponentScan: Configures
component scanning directives for use with
@Configuration
classes.Example
- Create the Dependency Class
package com.example.springcore; import org.springframework.stereotype.Component; // This annotation marks this class as a Spring-managed component @Component class Dependency { public void doSomething() { System.out.println("Dependency doing something"); } }
Explanation:
@Component
: This annotation marks theDependency
class as a Spring component, meaning Spring will automatically detect and create an instance of this class.
- Create the Consumer Class
package com.example.springcore; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; // This annotation marks this class as a Spring-managed component @Component class Consumer { private final Dependency dependency; // Constructor injection is performed here @Autowired public Consumer(Dependency dependency) { this.dependency = dependency; } public void performTask() { dependency.doSomething(); } }
Explanation:
@Component
: This annotation marks theConsumer
class as a Spring component.@Autowired
(Optional): This annotation tells Spring to use the constructor to inject theDependency
bean into theConsumer
bean. Since there’s only one constructor, Spring can infer the dependency injection without this annotation.
- Create the Configuration Class
package com.example.springcore; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; // This annotation marks this class as a configuration class @Configuration // This annotation tells Spring to scan the specified package for components @ComponentScan(basePackages = "com.example.springcore") public class AppConfig { }
Explanation:
@Configuration
: This annotation indicates that the class has@Bean
definition methods. Spring container can process the class to generate Spring Beans to be used in the application.@ComponentScan
: This annotation configures component scanning directives for use with@Configuration
classes. It tells Spring where to look for components (in this case, in thecom.example.springcore
package).
- Create the Main Application Class
package com.example.springcore; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class SpringCoreApplication { public static void main(String[] args) { // Create the application context using the AppConfig class ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); // Retrieve the Consumer bean from the context Consumer consumer = context.getBean(Consumer.class); // Perform the task consumer.performTask(); } }
Explanation:
ApplicationContext
: This is the central interface to provide configuration for an application. It is used to read the configuration metadata and instantiate, configure, and assemble the objects.AnnotationConfigApplicationContext
: This is a standalone application context, accepting@Configuration
-annotated classes as input.
Conclusion
Spring Core provides the foundation for building scalable and maintainable Java applications by leveraging IoC and DI principles. With features like annotation-based and Java-based configuration, Spring simplifies the development process while promoting best practices. This tutorial covered the basics of Spring Core, DI types, IoC, and essential annotations, making it beginner-friendly and providing a solid foundation for further exploration of the Spring Framework. By following these examples, you can effectively use Spring Core to manage dependencies and configure your application components.