BLOG POSTS
Spring Core Tutorial: Getting Started Guide

Spring Core Tutorial: Getting Started Guide

Spring Core is the foundational module of the Spring Framework that provides essential features like dependency injection, bean management, and application context configuration. Understanding Spring Core is crucial for any Java developer looking to build scalable, maintainable applications with proper separation of concerns. This guide will walk you through the fundamentals of Spring Core, from basic IoC concepts to advanced configuration techniques, helping you leverage this powerful framework in your projects.

How Spring Core Works

At its heart, Spring Core implements the Inversion of Control (IoC) pattern through dependency injection. Instead of objects creating their own dependencies, Spring’s container manages object creation and wires dependencies automatically. The ApplicationContext serves as the central registry that maintains bean definitions and their relationships.

The core components include:

  • BeanFactory: The basic container that provides dependency injection capabilities
  • ApplicationContext: An advanced container that extends BeanFactory with additional features
  • Bean Configuration: Metadata that tells Spring how to create and manage objects
  • Dependency Injection: The process of providing required dependencies to objects

Spring supports three main types of dependency injection: constructor injection, setter injection, and field injection. Constructor injection is generally recommended as it ensures immutable objects and fails fast if dependencies are missing.

Setting Up Your First Spring Core Project

Let’s create a basic Spring Core project from scratch. First, add the necessary dependencies to your Maven pom.xml:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>5.3.23</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.23</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>5.3.23</version>
    </dependency>
</dependencies>

Create a simple service class:

package com.example.service;

import org.springframework.stereotype.Service;

@Service
public class UserService {
    
    public String getUserInfo(Long userId) {
        return "User information for ID: " + userId;
    }
    
    public void createUser(String username, String email) {
        System.out.println("Creating user: " + username + " with email: " + email);
    }
}

Create a controller that depends on the service:

package com.example.controller;

import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class UserController {
    
    private final UserService userService;
    
    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }
    
    public void handleUserRequest(Long userId) {
        String userInfo = userService.getUserInfo(userId);
        System.out.println("Controller received: " + userInfo);
    }
}

Create a configuration class to enable component scanning:

package com.example.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
}

Finally, create your main application class:

package com.example;

import com.example.config.AppConfig;
import com.example.controller.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Application {
    
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        
        UserController controller = context.getBean(UserController.class);
        controller.handleUserRequest(12345L);
    }
}

Configuration Methods Comparison

Spring Core offers multiple ways to configure beans and dependencies. Here’s a comparison of the main approaches:

Configuration Type Pros Cons Best Use Case
XML Configuration Explicit, external to code, good for complex wiring Verbose, no compile-time checking, harder to maintain Legacy applications, complex bean definitions
Annotation-based Less verbose, compile-time checking, easier refactoring Configuration scattered across classes Most modern applications
Java Configuration Type-safe, refactoring-friendly, programmatic control More code to write Complex configuration logic, third-party integrations

Real-World Use Cases and Examples

Here are some practical scenarios where Spring Core shines:

Database Service Layer:

@Repository
public class UserRepository {
    
    @Autowired
    private DataSource dataSource;
    
    public User findById(Long id) {
        // Database logic here
        return new User(id, "John Doe", "john@example.com");
    }
}

@Service
@Transactional
public class UserBusinessService {
    
    private final UserRepository userRepository;
    private final EmailService emailService;
    
    public UserBusinessService(UserRepository userRepository, EmailService emailService) {
        this.userRepository = userRepository;
        this.emailService = emailService;
    }
    
    public void processUserRegistration(Long userId) {
        User user = userRepository.findById(userId);
        emailService.sendWelcomeEmail(user.getEmail());
    }
}

Configuration Properties Management:

@Component
@ConfigurationProperties(prefix = "app.database")
public class DatabaseConfig {
    
    private String url;
    private String username;
    private String password;
    private int maxConnections = 10;
    
    // Getters and setters
    public String getUrl() { return url; }
    public void setUrl(String url) { this.url = url; }
    
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    
    public String getPassword() { return password; }
    public void setPassword(String password) { this.password = password; }
    
    public int getMaxConnections() { return maxConnections; }
    public void setMaxConnections(int maxConnections) { this.maxConnections = maxConnections; }
}

Event-Driven Architecture:

@Component
public class OrderEventListener {
    
    @EventListener
    public void handleOrderCreated(OrderCreatedEvent event) {
        System.out.println("Processing order: " + event.getOrderId());
        // Send confirmation email, update inventory, etc.
    }
}

@Service
public class OrderService {
    
    @Autowired
    private ApplicationEventPublisher eventPublisher;
    
    public void createOrder(Order order) {
        // Save order logic
        eventPublisher.publishEvent(new OrderCreatedEvent(order.getId()));
    }
}

Advanced Features and Best Practices

Spring Core offers several advanced features that can significantly improve your application architecture:

Bean Scopes and Lifecycle Management:

@Component
@Scope("prototype")
public class PrototypeBean {
    
    @PostConstruct
    public void init() {
        System.out.println("PrototypeBean initialized");
    }
    
    @PreDestroy
    public void cleanup() {
        System.out.println("PrototypeBean destroyed");
    }
}

@Component
@Scope("singleton")
public class SingletonBean {
    
    private final PrototypeBean prototypeBean;
    
    public SingletonBean(@Lookup PrototypeBean prototypeBean) {
        this.prototypeBean = prototypeBean;
    }
}

Profile-based Configuration:

@Configuration
@Profile("development")
public class DevConfig {
    
    @Bean
    public DataSource dataSource() {
        return new H2DataSource("jdbc:h2:mem:testdb");
    }
}

@Configuration
@Profile("production")
public class ProdConfig {
    
    @Bean
    public DataSource dataSource() {
        return new PostgreSQLDataSource("jdbc:postgresql://prod-db:5432/app");
    }
}

Conditional Bean Registration:

@Configuration
public class ConditionalConfig {
    
    @Bean
    @ConditionalOnProperty(name = "cache.enabled", havingValue = "true")
    public CacheManager cacheManager() {
        return new RedisCacheManager();
    }
    
    @Bean
    @ConditionalOnMissingBean(CacheManager.class)
    public CacheManager noCacheManager() {
        return new NoOpCacheManager();
    }
}

Common Pitfalls and Troubleshooting

Here are the most frequent issues developers encounter with Spring Core:

Circular Dependencies: This happens when two beans depend on each other. Spring can handle some circular dependencies through setter injection, but constructor injection will fail.

// Problematic circular dependency
@Service
public class ServiceA {
    public ServiceA(ServiceB serviceB) { }
}

@Service
public class ServiceB {
    public ServiceB(ServiceA serviceA) { }
}

// Solution: Use @Lazy annotation
@Service
public class ServiceA {
    public ServiceA(@Lazy ServiceB serviceB) { }
}

Bean Not Found Errors: Usually caused by missing component scanning or incorrect package structures.

// Make sure your configuration includes the right packages
@ComponentScan(basePackages = {"com.example.service", "com.example.repository"})
public class AppConfig { }

Multiple Bean Candidates: When Spring finds multiple beans of the same type, use @Primary or @Qualifier.

@Service
@Primary
public class PrimaryEmailService implements EmailService { }

@Service
@Qualifier("backup")
public class BackupEmailService implements EmailService { }

// Inject specific implementation
@Autowired
@Qualifier("backup")
private EmailService emailService;

Performance Considerations and Optimization

Spring Core performance can be optimized through several strategies:

  • Use constructor injection over field injection for better performance and testability
  • Prefer singleton scope for stateless beans to reduce object creation overhead
  • Use @Lazy annotation for expensive beans that might not be needed immediately
  • Consider using @ConfigurationProperties instead of multiple @Value annotations
  • Enable Spring’s caching mechanisms for expensive operations

Application startup time can be measured and optimized:

@EventListener
public void handleContextRefreshed(ContextRefreshedEvent event) {
    ApplicationContext context = event.getApplicationContext();
    long startTime = context.getStartupDate();
    long currentTime = System.currentTimeMillis();
    System.out.println("Context startup took: " + (currentTime - startTime) + "ms");
}

For comprehensive information about Spring Core features and advanced configuration options, check the official Spring Framework documentation.

When deploying Spring applications, consider using robust hosting solutions like VPS hosting for development environments or dedicated servers for production workloads requiring guaranteed resources and performance.



This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.

This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.

Leave a reply

Your email address will not be published. Required fields are marked