Spring BootWhat is Spring Framework
Spring Boot

What is Spring Framework

Spring Framework is the foundation of the entire Spring ecosystem — a comprehensive, lightweight framework for building Java enterprise applications. It introduced dependency injection and aspect-oriented programming to mainstream Java development, and fundamentally changed how Java applications are built and structured.

The Problem Spring Solved

Before Spring, building Java enterprise applications meant using EJB (Enterprise JavaBeans) — a heavy, complex specification that required expensive application servers, generated mountains of boilerplate XML, and made testing nearly impossible. A simple database operation required dozens of lines of ceremony code. Rod Johnson published "Expert One-on-One J2EE Design and Development" in 2002, demonstrating that enterprise Java could be done better. The code from that book became Spring Framework, released in 2003. The premise was simple: Java enterprise development should be possible without EJB, using plain Java objects (POJOs) wired together by a lightweight container. Spring didn't just simplify Java development — it redefined it. Dependency injection, which Spring popularized, is now a standard design pattern across virtually every modern programming ecosystem.

The Core Concept — Inversion of Control

Spring's foundation is Inversion of Control (IoC) — a design principle where the framework controls object creation and wiring rather than your code doing it manually. Instead of objects creating their own dependencies with new, they declare what they need and Spring provides it. The IoC Container is the heart of Spring. It reads your configuration (annotations, XML, or Java config), creates all the beans (Spring-managed objects), injects dependencies, and manages their lifecycle from creation to destruction. This means your classes don't need to know where their dependencies come from. A UserService doesn't create a UserRepository — it declares that it needs one, and Spring provides it. This decoupling makes code testable, modular, and easy to swap implementations.
Java
// Without Spring — UserService manually creates its dependencies:
public class UserService {
    private UserRepository repository = new UserRepositoryImpl(); // tight coupling
    private EmailService emailService = new EmailServiceImpl();   // hard to test

    public void registerUser(User user) {
        repository.save(user);
        emailService.sendWelcome(user.getEmail());
    }
}

// With Spring — dependencies are injected (Dependency Injection):
@Service
public class UserService {
    private final UserRepository repository;
    private final EmailService emailService;

    // Constructor injection — Spring provides both dependencies:
    public UserService(UserRepository repository, EmailService emailService) {
        this.repository = repository;
        this.emailService = emailService;
    }

    public void registerUser(User user) {
        repository.save(user);
        emailService.sendWelcome(user.getEmail());
    }
}
// UserService doesn't know or care which implementation it gets.
// In production: real DB and real email service.
// In tests: mock implementations injected instead.

The Spring Modules

Spring isn't a single library — it's a modular ecosystem. You use only the modules your application needs. The core modules are: Spring Core and Beans — The IoC container, dependency injection, bean lifecycle management. Everything else is built on this. Spring Context — Application context that extends the bean factory with internationalization, event publishing, resource loading, and annotation-driven configuration. Spring AOP — Aspect-Oriented Programming. Cross-cutting concerns like logging, security, transactions, and caching can be applied across multiple classes without modifying their code. Spring Data Access — JDBC template, ORM integration (Hibernate, JPA), transaction management. Eliminates boilerplate database code. Spring MVC — Model-View-Controller web framework. Handles HTTP requests, routing, view resolution, and REST API building. Spring Security — Authentication, authorization, CSRF protection, OAuth2 integration. Secures web applications and REST APIs. Spring Test — Testing utilities for integration tests, MockMVC for testing controllers, transaction rollback in tests.

Dependency Injection — The Three Ways

Spring supports three styles of dependency injection. Constructor injection is the recommended approach for mandatory dependencies.
Java
// 1. Constructor Injection (RECOMMENDED):
@Service
public class OrderService {
    private final OrderRepository repository;
    private final PaymentService paymentService;

    // Spring auto-detects single constructor — @Autowired optional in modern Spring:
    public OrderService(OrderRepository repository, PaymentService paymentService) {
        this.repository = repository;
        this.paymentService = paymentService;
    }
}
// Benefits: fields can be final, NullPointerException impossible,
//           testable without Spring context (just call new OrderService(mock, mock))

// 2. Setter Injection (for optional dependencies):
@Service
public class NotificationService {
    private EmailClient emailClient;

    @Autowired(required = false)
    public void setEmailClient(EmailClient emailClient) {
        this.emailClient = emailClient;
    }
}

// 3. Field Injection (convenient but avoid in production code):
@Service
public class ProductService {
    @Autowired
    private ProductRepository repository;  // can't be final, hard to test
}

Spring AOP — Cross-Cutting Concerns

Aspect-Oriented Programming (AOP) is Spring's solution to code that spans multiple classes — logging, security checks, transaction management, performance monitoring. Instead of copying this code into every method, you define it once in an Aspect and Spring weaves it in automatically.
Java
// Without AOP — logging duplicated in every service method:
public class OrderService {
    public Order createOrder(OrderRequest request) {
        log.info("createOrder called with: {}", request);  // duplicated
        long start = System.currentTimeMillis();
        Order order = processOrder(request);
        log.info("createOrder took {}ms", System.currentTimeMillis() - start); // duplicated
        return order;
    }
}

// With AOP — logging defined once, applied everywhere:
@Aspect
@Component
public class LoggingAspect {

    // Applies to ALL methods in ANY class in the service package:
    @Around("execution(* com.example.service.*.*(..))")
    public Object logExecution(ProceedingJoinPoint joinPoint) throws Throwable {
        String method = joinPoint.getSignature().getName();
        log.info("Calling: {}", method);
        long start = System.currentTimeMillis();

        Object result = joinPoint.proceed();   // call the actual method

        log.info("{} took {}ms", method, System.currentTimeMillis() - start);
        return result;
    }
}
// OrderService.createOrder() now has logging applied automatically.
// Zero changes to OrderService. Zero code duplication.

Spring Bean Lifecycle

Every object managed by the Spring IoC container is called a bean. Spring controls the complete lifecycle — creation, initialization, use, and destruction. Understanding this lifecycle helps you write initialization and cleanup code correctly.
Java
@Component
public class DatabaseConnectionPool {

    private DataSource dataSource;

    // Called by Spring after all dependencies are injected:
    @PostConstruct
    public void initialize() {
        // Safe to use dependencies here — all injected before this is called
        this.dataSource = createDataSource();
        System.out.println("Connection pool initialized with " + poolSize + " connections");
    }

    // Called by Spring just before the bean is destroyed:
    @PreDestroy
    public void shutdown() {
        // Clean up resources — close connections, flush buffers, etc.
        dataSource.close();
        System.out.println("Connection pool shut down");
    }
}

// Bean scopes — how many instances Spring creates:
@Component
@Scope("singleton")   // DEFAULT — one shared instance per container
public class AppConfig { }

@Component
@Scope("prototype")   // new instance every time it's requested
public class RequestProcessor { }

@Component
@Scope("request")     // one per HTTP request (web applications only)
public class RequestContext { }

@Component
@Scope("session")     // one per HTTP session (web applications only)
public class UserSession { }

Why Spring Became the Standard

Spring became the dominant Java framework for several compounding reasons: Testability — Because Spring injects dependencies rather than letting classes create them, you can test any class by passing mock dependencies to its constructor. No Spring container needed in unit tests. Non-invasive — Your business logic classes (UserService, OrderProcessor) don't extend Spring classes or implement Spring interfaces. They're plain Java objects. Spring wraps them at runtime without touching them. Modularity — Use only what you need. Building a REST API? Add Spring MVC. Need database access? Add Spring Data. Need security? Add Spring Security. Each module is independent and well-integrated. Ecosystem — Spring has official integrations with every major technology: Hibernate, Redis, Kafka, RabbitMQ, MongoDB, Elasticsearch, AWS, Azure, Kubernetes. Whatever you need, there's a Spring module for it. Community and maturity — 20+ years of production use across thousands of enterprise applications. Battle-tested, well-documented, actively maintained. Real-world impact: Netflix, Amazon, LinkedIn, Alibaba, and thousands of banks and healthcare providers run Spring-based backends serving billions of requests daily.