Lecture 30: Factory Design Pattern in Spring

BMC201 - Web Technology

Mr. Prashant Kumar Nag

2026-03-16

Lecture 30

Factory Design Pattern in Spring

Week 8 | Unit IV: Spring Framework Basics
BMC201 - Web Technology
Mr. Prashant Kumar Nag, Assistant Professor

Learning Objectives


  • Understand Factory pattern intent
  • Locate factory behavior in Spring container
  • Apply a simple factory example

Prerequisites


  • Core Java OOP concepts and interface-based design
  • Basic understanding of Servlets/JSP request flow from Unit III
  • Revision of Lecture 29 before moving into Factory Design Pattern in Spring

Syllabus Mapping


  • Unit IV topic focus: Factory Design Pattern in Spring
  • CO alignment: implementation understanding + architecture reasoning
  • Assessment alignment: short definitions + long implementation/design questions

Agenda


  • 5-minute recap from previous lecture
  • Concept deep dive: Factory Design Pattern in Spring
  • Code/configuration walkthrough and output analysis
  • Debug checklist and exam-oriented summary

Introduction


Factory pattern delegates object creation to dedicated logic.

Think About It


How can clients avoid hardcoded constructors?

What Is Factory Pattern?


Factory Pattern is a creational design pattern that provides an interface for creating objects without specifying their exact classes.

Key Principles:

  • Encapsulate object creation logic
  • Client code depends on abstractions, not concrete classes
  • Easy to extend with new types without modifying client code

The factory centralizes and controls object instantiation.

Intent of Factory Pattern


Problem: When you have multiple classes implementing the same interface and the client needs to choose which one to instantiate.

Solution: Create a factory that decides which class to instantiate based on input parameters.

Benefits:

  • Loose coupling between client and concrete classes
  • Single place to change instantiation logic
  • Easy to add new types without changing client code

Factory Pattern Variants


Three common factory pattern variants:

Pattern Description Complexity
Simple Factory Static method creates objects Low
Factory Method Subclasses decide which class to instantiate Medium
Abstract Factory Creates families of related objects High

Spring primarily uses Simple Factory and Factory Method patterns.

Code Without Factory Pattern


// Client code tightly coupled to concrete classes
public class PaymentProcessor {
    public void processPayment(String method, double amount) {
        if (method.equals("CREDIT_CARD")) {
            CreditCardGateway gateway = new CreditCardGateway();
            gateway.charge(amount);
        } else if (method.equals("UPI")) {
            UpiGateway gateway = new UpiGateway();
            gateway.transfer(amount);
        } else if (method.equals("WALLET")) {
            WalletGateway gateway = new WalletGateway();
            gateway.deduct(amount);
        }
        // Adding new payment method requires modifying this code
    }
}

This violates Open-Closed Principle and creates tight coupling.

Code With Factory Pattern


// Common interface
public interface PaymentGateway {
    void process(double amount);
}

// Factory
public class PaymentGatewayFactory {
    public static PaymentGateway create(String method) {
        switch (method) {
            case "CREDIT_CARD": return new CreditCardGateway();
            case "UPI": return new UpiGateway();
            case "WALLET": return new WalletGateway();
            default: throw new IllegalArgumentException("Unknown method");
        }
    }
}

// Client code
PaymentGateway gateway = PaymentGatewayFactory.create("UPI");
gateway.process(amount);

Client depends only on interface; factory handles concrete instantiation.

BeanFactory in Spring


BeanFactory is Spring’s core container interface for accessing beans.

Key characteristics:

  • Lazy initialization — beans created on first request
  • Basic DI support
  • Lightweight container
  • Foundation for ApplicationContext
BeanFactory factory = new XmlBeanFactory(
    new ClassPathResource("beans.xml"));
UserService service = factory.getBean(UserService.class);

BeanFactory is the root interface of Spring’s IoC container.

ApplicationContext in Spring


ApplicationContext extends BeanFactory with enterprise features:

  • Eager bean initialization (by default)
  • Automatic BeanPostProcessor registration
  • Event publication mechanism
  • MessageSource for i18n
  • Application-layer specific contexts (WebApplicationContext)
ApplicationContext ctx = 
    new AnnotationConfigApplicationContext(AppConfig.class);
OrderService orderService = ctx.getBean(OrderService.class);

ApplicationContext is the preferred container for most applications.

BeanFactory vs ApplicationContext


Feature BeanFactory ApplicationContext
Bean Instantiation Lazy Eager (default)
BeanPostProcessor Manual registration Automatic
Event Handling Not supported Supported
i18n Support Not supported Supported
AOP Integration Limited Full support
Use Case Resource-constrained apps Enterprise apps

Recommendation: Use ApplicationContext unless you have specific constraints.

FactoryBean Interface


FactoryBean allows custom bean creation logic.

public interface FactoryBean<T> {
    T getObject() throws Exception;      // Create instance
    Class<?> getObjectType();            // Type of object
    boolean isSingleton();               // Singleton or prototype
}

Use when:

  • Bean creation is complex
  • Initialization requires multiple steps
  • You need to create third-party objects that aren’t Spring-aware

FactoryBean is itself a bean that produces other beans.

FactoryBean Implementation Example


@Component
public class ConnectionPoolFactoryBean 
    implements FactoryBean<DataSource> {
    
    @Value("${db.url}") private String url;
    @Value("${db.username}") private String username;
    @Value("${db.password}") private String password;
    
    @Override
    public DataSource getObject() throws Exception {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl(url);
        config.setUsername(username);
        config.setPassword(password);
        config.setMaximumPoolSize(10);
        return new HikariDataSource(config);
    }
    
    @Override
    public Class<?> getObjectType() {
        return DataSource.class;
    }
    
    @Override
    public boolean isSingleton() {
        return true;
    }
}

@Bean as Factory Method


@Bean methods in @Configuration classes act as factory methods:

@Configuration
public class AppConfig {
    
    @Bean
    public DataSource dataSource() {  // Factory method
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mysql://localhost/mydb");
        config.setUsername("user");
        config.setPassword("pass");
        return new HikariDataSource(config);
    }
    
    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

Each @Bean method is a factory that Spring calls to create beans.

Static Factory Method Pattern


In XML configuration, you can reference static factory methods:

<bean id="calendar" 
      class="java.util.Calendar"
      factory-method="getInstance"/>

In Java Config:

@Configuration
public class CalendarConfig {
    @Bean
    public Calendar calendar() {
        return Calendar.getInstance();  // Static factory
    }
}

Instance Factory Method Pattern


// Factory class
public class ReportGeneratorFactory {
    public ReportGenerator createPdfGenerator() {
        return new PdfReportGenerator();
    }
    
    public ReportGenerator createExcelGenerator() {
        return new ExcelReportGenerator();
    }
}

// Configuration
@Configuration
public class ReportConfig {
    @Bean
    public ReportGeneratorFactory reportFactory() {
        return new ReportGeneratorFactory();
    }
    
    @Bean
    public ReportGenerator pdfGenerator(
            ReportGeneratorFactory factory) {
        return factory.createPdfGenerator();
    }
}

Factory Pattern in Spring


flowchart TD
    A["Client Code"] --> B["Factory\n(ApplicationContext)"]
    B --> C{Bean Type?}
    C -->|Service| D["ServiceBean"]
    C -->|Repository| E["RepositoryBean"]
    C -->|Controller| F["ControllerBean"]
    D --> G["Return Bean Instance"]
    E --> G
    F --> G
    G --> A

Spring’s container acts as a universal factory for all beans in your application.

Benefits of Factory in Spring


Why factory pattern is essential in Spring:

  1. Centralized Creation — All beans created in one place
  2. Consistent Lifecycle — Initialization callbacks applied uniformly
  3. Dependency Resolution — Factory wires dependencies automatically
  4. Scope Management — Factory controls singleton/prototype behavior
  5. Proxy Creation — Factory wraps beans with AOP proxies transparently
  6. Configuration Externalization — Creation details outside business code

The factory pattern is the foundation of Spring’s IoC container.

Real-World Factory Example


// Strategy interface
public interface NotificationStrategy {
    void send(String recipient, String message);
}

// Implementations
@Component("email")
public class EmailNotification implements NotificationStrategy { }

@Component("sms")
public class SmsNotification implements NotificationStrategy { }

// Factory
@Component
public class NotificationFactory {
    @Autowired
    private Map<String, NotificationStrategy> strategies;
    
    public NotificationStrategy getStrategy(String channel) {
        NotificationStrategy strategy = strategies.get(channel);
        if (strategy == null) {
            throw new IllegalArgumentException("Unknown channel: " + channel);
        }
        return strategy;
    }
}

Advanced Factory Techniques


@Component
public class PaymentGatewayFactory {
    
    @Autowired
    private ApplicationContext context;
    
    public PaymentGateway createGateway(String type) {
        // Create prototype bean dynamically
        return context.getBean(type + "Gateway", PaymentGateway.class);
    }
}

// Usage
@Configuration
public class PaymentConfig {
    @Bean
    @Scope("prototype")
    public PaymentGateway creditCardGateway() {
        return new CreditCardGateway();
    }
    
    @Bean
    @Scope("prototype")
    public PaymentGateway upiGateway() {
        return new UpiGateway();
    }
}

Factory Pattern Best Practices


Guidelines for using factories in Spring:

  1. Prefer @Bean methods over FactoryBean for simple cases
  2. Use FactoryBean when creation is complex or multi-step
  3. Inject ApplicationContext sparingly (creates coupling)
  4. Document factory logic — explain why custom factory is needed
  5. Keep factories stateless — avoid mutable state in factory beans
  6. Return interfaces — factories should return abstractions, not concrete classes

Factories should simplify creation, not complicate it.

Common Factory Pattern Mistakes


Mistake 1: Returning null from factory

// BAD: Can cause NullPointerException
@Bean
public DataSource dataSource() {
    return null;  // Spring still registers bean as null
}

Mistake 2: Service Locator anti-pattern

// AVOID: Defeats DI purpose
public class OrderService {
    public void process() {
        PaymentService service = 
            context.getBean(PaymentService.class);  // Service Locator
    }
}

Use dependency injection instead of manual bean lookups.

Code Walkthrough: Complete Factory


// Step 1: Define interface
public interface ReportGenerator {
    byte[] generate(ReportData data);
}

// Step 2: Implementations
@Component("pdf")
public class PdfReportGenerator implements ReportGenerator { }

@Component("excel")
public class ExcelReportGenerator implements ReportGenerator { }

// Step 3: Factory
@Component
public class ReportGeneratorFactory {
    @Autowired
    private Map<String, ReportGenerator> generators;
    
    public ReportGenerator get(String format) {
        return generators.get(format);
    }
}

// Step 4: Client
@Service
public class ReportService {
    @Autowired private ReportGeneratorFactory factory;
    
    public byte[] createReport(String format, ReportData data) {
        return factory.get(format).generate(data);
    }
}

Memory Booster


Syllabus memory points for Factory Design Pattern in Spring:

  • Core recall: BeanFactory/ApplicationContext object creation
  • Exam compare: Direct new object creation vs factory-managed creation
  • Practical anchor: Implement factory-style bean creation flow

Live Demo


Live implementation for Factory Design Pattern in Spring:

?? Open Demo: Lecture 30 - Factory Design Pattern in Spring

Demo checklist: - implement the key flow for this lecture - verify expected output for one success case - trigger one failure case and explain the fix

Resources & References


Structured Debug Checklist


  1. verify the primary API usage for Factory Design Pattern in Spring is correct (imports, method names, config)
  2. check request/bean/session flow and object lifecycle assumptions
  3. inspect server logs for the first exception (not just the final symptom)
  4. reproduce one failing case and one passing case before finalizing fixes

Exam Preparation Questions: Short


  • Define Factory Design Pattern in Spring with one practical use case.
  • Write/identify the key API or construct: BeanFactory/ApplicationContext object creation.
  • Differentiate: Direct new object creation vs factory-managed creation.
  • Mention one common implementation error and correction.

Exam Preparation Questions: Long


  • Explain Factory Design Pattern in Spring with architecture/flow and implementation steps.
  • Write a structured answer comparing two approaches used in this topic.
  • Discuss debugging strategy for this topic with likely failure points.

Practice Task


  • Implement: Implement factory-style bean creation flow.
  • Add console/log output to validate flow step-by-step.
  • Document one bug you encountered and the exact fix.

Checklist


Can you:

  • explain Factory Design Pattern in Spring in your own words?
  • implement a basic example end-to-end?
  • identify and fix one common runtime issue?

Next Lecture


  • Topic: Lecture 31 - Strategy Design Pattern in Spring
  • Preparation required: revise this lecture summary and code walkthrough

Questions?

Next: Lecture 31