Unit V: Spring Framework Concepts

Understanding enterprise Java development with Spring

Important Note

This unit covers Spring Framework concepts at a theoretical and conceptual level for exam preparation. It does not include production-ready configurations or step-by-step tutorials. Focus on understanding the principles, patterns, and terminology.

Introduction to Spring Framework

Definition

Spring is a comprehensive framework for building enterprise Java applications. It provides infrastructure support and simplifies the development of Java applications by promoting good design practices.

Key Features

Spring Modules

Module Purpose
Spring Core IoC and Dependency Injection
Spring AOP Aspect-Oriented Programming support
Spring MVC Web application framework
Spring Data Data access abstraction
Spring Security Authentication and authorization
Spring Boot Rapid application development with auto-configuration

Dependency Injection (DI)

Definition

Dependency Injection is a design pattern where an object receives its dependencies from an external source rather than creating them itself. The container "injects" the required dependencies into the object.

Benefits of DI

Types of Dependency Injection

Type Description Usage
Constructor Injection Dependencies passed via constructor Recommended for mandatory dependencies
Setter Injection Dependencies set via setter methods Optional dependencies
Field Injection Dependencies injected directly into fields Convenient but less testable
Dependency Injection Conceptual Example
// WITHOUT Dependency Injection (tight coupling)
class OrderService {
    private EmailService emailService;
    
    public OrderService() {
        // Creates its own dependency - tightly coupled
        this.emailService = new EmailService();
    }
}

// WITH Dependency Injection (loose coupling)
class OrderService {
    private EmailService emailService;
    
    // Constructor Injection - dependency provided externally
    public OrderService(EmailService emailService) {
        this.emailService = emailService;
    }
}
Spring DI Examples
// 1. Constructor Injection (Recommended)
@Service
public class OrderService {
    private final EmailService emailService;
    
    @Autowired  // Optional since Spring 4.3 for single constructor
    public OrderService(EmailService emailService) {
        this.emailService = emailService;
    }
}

// 2. Setter Injection
@Service
public class OrderService {
    private EmailService emailService;
    
    @Autowired
    public void setEmailService(EmailService emailService) {
        this.emailService = emailService;
    }
}

// 3. Field Injection
@Service
public class OrderService {
    @Autowired
    private EmailService emailService;
}

Exam Tip

Constructor injection is preferred because: (1) dependencies are clearly visible, (2) objects can be immutable (final fields), (3) easier to test without Spring container.

Inversion of Control (IoC)

Definition

Inversion of Control is a design principle where the control of object creation and dependency management is transferred from the application code to a container or framework. The framework "calls" your code rather than your code calling the framework.

IoC Container

The Spring IoC container is responsible for:

Types of IoC Containers

Container Interface Description
BeanFactory org.springframework.beans.factory.BeanFactory Basic container with lazy initialization
ApplicationContext org.springframework.context.ApplicationContext Advanced container with eager initialization, AOP, i18n support
IoC Container Concept
// Traditional approach (no IoC)
public class Application {
    public static void main(String[] args) {
        // Application creates and manages objects
        EmailService emailService = new EmailService();
        OrderService orderService = new OrderService(emailService);
        orderService.processOrder();
    }
}

// With IoC Container (Spring)
public class Application {
    public static void main(String[] args) {
        // Container creates and manages objects
        ApplicationContext context = 
            new AnnotationConfigApplicationContext(AppConfig.class);
        
        // Get bean from container - dependencies already injected
        OrderService orderService = context.getBean(OrderService.class);
        orderService.processOrder();
    }
}

Note

IoC is the principle; Dependency Injection is one implementation of IoC. Spring uses DI to achieve IoC.

Aspect-Oriented Programming (AOP)

Definition

AOP is a programming paradigm that allows separation of cross-cutting concerns (concerns that affect multiple parts of an application) from the main business logic. Examples include logging, security, transaction management.

AOP Terminology

Term Definition
Aspect A module that encapsulates a cross-cutting concern
Join Point A point during execution (method call, exception)
Advice Action taken at a join point (before, after, around)
Pointcut Expression that matches join points
Target Object Object being advised (proxied)
Weaving Linking aspects with target objects

Types of Advice

Advice Type Annotation When Executed
Before @Before Before the join point
After Returning @AfterReturning After successful completion
After Throwing @AfterThrowing After exception is thrown
After (Finally) @After After join point (regardless of outcome)
Around @Around Wraps the join point (before and after)
AOP Conceptual Example
// Aspect for logging
@Aspect
@Component
public class LoggingAspect {
    
    // Pointcut - matches all methods in service package
    @Before("execution(* com.example.service.*.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("Executing: " + joinPoint.getSignature().getName());
    }
    
    @AfterReturning(
        pointcut = "execution(* com.example.service.*.*(..))",
        returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        System.out.println("Completed: " + joinPoint.getSignature().getName());
    }
    
    @Around("execution(* com.example.service.*.*(..))")
    public Object logAround(ProceedingJoinPoint pjp) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = pjp.proceed();  // Execute actual method
        long duration = System.currentTimeMillis() - start;
        System.out.println("Execution time: " + duration + "ms");
        return result;
    }
}

Exam Tip

Common cross-cutting concerns suitable for AOP: Logging, Security, Transaction Management, Caching, Error Handling, Performance Monitoring.

Bean Scopes

Definition

Bean scope defines the lifecycle and visibility of a bean within the Spring container. It determines how many instances of a bean are created and how they are shared.

Types of Bean Scopes

Scope Description Usage
singleton Single instance per Spring container (default) Stateless beans, services
prototype New instance created for each request Stateful beans
request One instance per HTTP request (web only) Request-specific data
session One instance per HTTP session (web only) User session data
application One instance per ServletContext (web only) Application-wide data
Bean Scope Examples
// Singleton scope (default)
@Component
@Scope("singleton")  // Optional - singleton is default
public class UserService {
    // Same instance shared across all requests
}

// Prototype scope
@Component
@Scope("prototype")
public class ShoppingCart {
    // New instance created each time bean is requested
}

// Request scope (web applications)
@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestData {
    // One instance per HTTP request
}

// Session scope (web applications)
@Component
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class UserSession {
    // One instance per HTTP session
}

Common Mistake

Injecting a prototype-scoped bean into a singleton bean results in only one instance of the prototype bean being created. Use @Lookup or ObjectFactory for proper prototype injection.

Autowiring

Definition

Autowiring is Spring's mechanism for automatically resolving and injecting dependencies. Spring can automatically discover beans and inject them into dependent beans.

Autowiring Modes

Mode Description
no No autowiring (default in XML)
byName Match by bean name
byType Match by bean type
constructor Match by constructor argument type
Autowiring Examples
// @Autowired - injects by type
@Service
public class OrderService {
    
    @Autowired
    private UserRepository userRepository;  // Field injection
    
    @Autowired
    public OrderService(PaymentService paymentService) {  // Constructor
        this.paymentService = paymentService;
    }
}

// @Qualifier - when multiple beans of same type exist
public interface PaymentService { }

@Service("creditCard")
public class CreditCardPayment implements PaymentService { }

@Service("paypal")
public class PayPalPayment implements PaymentService { }

@Service
public class OrderService {
    @Autowired
    @Qualifier("creditCard")  // Specifies which implementation
    private PaymentService paymentService;
}

// @Primary - default bean when multiple exist
@Service
@Primary
public class CreditCardPayment implements PaymentService { }

Spring Annotations Overview

Stereotype Annotations

Annotation Purpose
@Component Generic Spring-managed component
@Service Service layer class (business logic)
@Repository Data access layer class (DAO)
@Controller Web controller (MVC)
@RestController REST API controller (@Controller + @ResponseBody)

Configuration Annotations

Annotation Purpose
@Configuration Marks class as source of bean definitions
@Bean Declares a bean to be managed by Spring
@ComponentScan Enables component scanning
@PropertySource Specifies property file location
@Value Injects values from properties
Configuration Class Example
@Configuration
@ComponentScan(basePackages = "com.example")
@PropertySource("classpath:application.properties")
public class AppConfig {
    
    @Value("${app.name}")
    private String appName;
    
    @Bean
    public DataSource dataSource() {
        // Create and configure DataSource
        return new DriverManagerDataSource();
    }
    
    @Bean
    @Scope("prototype")
    public ReportGenerator reportGenerator() {
        return new ReportGenerator();
    }
}

Bean Lifecycle

Lifecycle Stages

  1. Instantiation: Container creates bean instance
  2. Populate Properties: Dependencies are injected
  3. BeanNameAware: setBeanName() called
  4. BeanFactoryAware: setBeanFactory() called
  5. ApplicationContextAware: setApplicationContext() called
  6. Pre-Initialization: BeanPostProcessor.postProcessBeforeInitialization()
  7. InitializingBean: afterPropertiesSet() called
  8. Custom init-method: @PostConstruct or init-method
  9. Post-Initialization: BeanPostProcessor.postProcessAfterInitialization()
  10. Bean Ready for Use
  11. DisposableBean: destroy() called on shutdown
  12. Custom destroy-method: @PreDestroy or destroy-method
Bean Lifecycle Callbacks
@Component
public class MyBean {
    
    public MyBean() {
        System.out.println("1. Constructor called");
    }
    
    @Autowired
    public void setDependency(SomeDependency dep) {
        System.out.println("2. Dependencies injected");
    }
    
    @PostConstruct
    public void init() {
        System.out.println("3. PostConstruct - initialization");
    }
    
    @PreDestroy
    public void cleanup() {
        System.out.println("4. PreDestroy - cleanup before destruction");
    }
}

// Alternative using interfaces
@Component
public class AnotherBean implements InitializingBean, DisposableBean {
    
    @Override
    public void afterPropertiesSet() {
        System.out.println("InitializingBean.afterPropertiesSet()");
    }
    
    @Override
    public void destroy() {
        System.out.println("DisposableBean.destroy()");
    }
}

Exam Tip

Prefer @PostConstruct and @PreDestroy annotations over implementing interfaces. They are part of standard Java (JSR-250) and don't couple your code to Spring.

Spring Boot Overview

Definition

Spring Boot is an extension of the Spring framework that simplifies the creation of stand-alone, production-grade Spring applications with minimal configuration.

Key Features

Spring Boot Starters

Starter Purpose
spring-boot-starter-web Web applications with Spring MVC
spring-boot-starter-data-jpa JPA with Hibernate
spring-boot-starter-security Spring Security
spring-boot-starter-test Testing libraries
Spring Boot Application Structure
// Main application class
@SpringBootApplication  // Combines @Configuration, @EnableAutoConfiguration, @ComponentScan
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

// application.properties
// server.port=8080
// spring.datasource.url=jdbc:mysql://localhost:3306/mydb
// spring.datasource.username=root
// spring.datasource.password=password

Spring Boot Runners

CommandLineRunner and ApplicationRunner
// CommandLineRunner - receives arguments as String array
@Component
public class MyRunner implements CommandLineRunner {
    @Override
    public void run(String... args) {
        System.out.println("Application started with args");
        for (String arg : args) {
            System.out.println(arg);
        }
    }
}

// ApplicationRunner - receives parsed ApplicationArguments
@Component
public class AnotherRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) {
        System.out.println("Non-option args: " + args.getNonOptionArgs());
        System.out.println("Option names: " + args.getOptionNames());
    }
}

Logging in Spring Boot

Logging Example
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Service
public class OrderService {
    private static final Logger logger = LoggerFactory.getLogger(OrderService.class);
    
    public void processOrder(Order order) {
        logger.debug("Processing order: {}", order.getId());
        logger.info("Order processed successfully");
        logger.warn("Low inventory warning");
        logger.error("Failed to process order", exception);
    }
}

// application.properties logging configuration
// logging.level.root=INFO
// logging.level.com.example=DEBUG
// logging.file.name=application.log

REST API Basics

Definition

REST (Representational State Transfer) is an architectural style for designing networked applications. It uses HTTP methods to perform CRUD operations on resources.

HTTP Methods and CRUD

HTTP Method CRUD Operation Description
GET Read Retrieve resource(s)
POST Create Create new resource
PUT Update Update entire resource
PATCH Update Partial update
DELETE Delete Remove resource

REST Controller Annotations

Annotation Purpose
@RestController Marks class as REST controller
@RequestMapping Maps HTTP requests to handler methods
@GetMapping Maps GET requests
@PostMapping Maps POST requests
@PutMapping Maps PUT requests
@DeleteMapping Maps DELETE requests
@PathVariable Extracts value from URI path
@RequestBody Binds request body to object
@RequestParam Extracts query parameters
REST Controller Example
@RestController
@RequestMapping("/api/users")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    // GET /api/users
    @GetMapping
    public List<User> getAllUsers() {
        return userService.findAll();
    }
    
    // GET /api/users/5
    @GetMapping("/{id}")
    public User getUserById(@PathVariable Long id) {
        return userService.findById(id);
    }
    
    // POST /api/users
    @PostMapping
    public User createUser(@RequestBody User user) {
        return userService.save(user);
    }
    
    // PUT /api/users/5
    @PutMapping("/{id}")
    public User updateUser(@PathVariable Long id, @RequestBody User user) {
        return userService.update(id, user);
    }
    
    // DELETE /api/users/5
    @DeleteMapping("/{id}")
    public void deleteUser(@PathVariable Long id) {
        userService.delete(id);
    }
    
    // GET /api/users/search?name=John
    @GetMapping("/search")
    public List<User> searchUsers(@RequestParam String name) {
        return userService.findByName(name);
    }
}

Exam Tip

@RestController = @Controller + @ResponseBody. It automatically serializes return objects to JSON/XML.