Spring Framework Tutorial

Software Setup and Configuration (STS/Eclipse/IntelliJ)

Core Spring

Spring Annotations

Spring Data

Spring JDBC

Spring Security

Spring - Dependency Injection with Factory Method

In Spring, apart from directly instantiating beans using the constructor or setter methods, you can also define beans that are created through a static or instance factory method. This can be useful in scenarios where:

  1. The class does not expose a public constructor.
  2. You want to delegate the creation of the bean to a separate factory class.
  3. You need more complex creation logic than a simple constructor call.

Let's dive into an example of how you can achieve Dependency Injection using factory methods in Spring.

1. Static Factory Method:

Suppose we have a Car interface and its implementation Sedan:

public interface Car {
    void drive();
}

public class Sedan implements Car {

    private Sedan() {}  // private constructor

    public static Sedan createInstance() {
        return new Sedan();
    }

    @Override
    public void drive() {
        System.out.println("Driving a Sedan!");
    }
}

In this case, the Sedan class does not have a public constructor. We have a static createInstance method that provides an instance.

XML Configuration:

<bean id="sedanCar" class="com.example.Sedan" factory-method="createInstance"/>

2. Instance Factory Method:

Now, let's consider an example where we delegate the creation of the bean to another factory class.

Here's our Car interface and a factory class CarFactory:

public interface Car {
    void drive();
}

public class SportsCar implements Car {

    @Override
    public void drive() {
        System.out.println("Driving a Sports Car!");
    }
}

public class CarFactory {
    
    public Car createSportsCar() {
        return new SportsCar();
    }
}

XML Configuration:

<bean id="carFactory" class="com.example.CarFactory"/>

<bean id="sportsCar" factory-bean="carFactory" factory-method="createSportsCar"/>

In this case, the sportsCar bean will be created using the createSportsCar method of the carFactory bean.

Using the Beans:

public class App {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        
        Car sedan = context.getBean("sedanCar", Car.class);
        sedan.drive();
        
        Car sportsCar = context.getBean("sportsCar", Car.class);
        sportsCar.drive();
    }
}

Output:

Driving a Sedan!
Driving a Sports Car!

By using the factory method approach, you can have more control over the instantiation of your beans. You can include conditional logic, perform additional configuration, or even pool objects if required.

  1. Factory Method Dependency Injection in Spring:

    • Factory methods in Spring involve creating and returning instances of a class.
    // UserServiceFactory.java
    public class UserServiceFactory {
    
        public static UserService createUserService() {
            return new UserService();
        }
    }
    
  2. How to use factory methods for Dependency Injection in Spring:

    • Use factory methods to create and inject dependencies into Spring beans.
    // AppConfig.java
    @Configuration
    public class AppConfig {
    
        @Bean
        public UserService userService() {
            return UserServiceFactory.createUserService();
        }
    }
    
  3. Configuring dependencies with factory methods in Spring:

    • Configure Spring beans using factory methods to create and initialize dependencies.
    // AppConfig.java
    @Configuration
    public class AppConfig {
    
        @Bean
        public ProductService productService() {
            return ProductFactory.createProductService();
        }
    }
    
  4. FactoryBean for custom factory methods in Spring DI:

    • Implement a custom FactoryBean for more advanced control over factory methods.
    // CustomFactoryBean.java
    public class CustomFactoryBean implements FactoryBean<UserService> {
    
        @Override
        public UserService getObject() throws Exception {
            return new UserService();
        }
    
        @Override
        public Class<?> getObjectType() {
            return UserService.class;
        }
    
        @Override
        public boolean isSingleton() {
            return true;
        }
    }
    
  5. Creating and using factory methods in Spring framework:

    • Create factory methods in a separate class and use them to instantiate Spring beans.
    // AppConfig.java
    @Configuration
    public class AppConfig {
    
        @Bean
        public OrderService orderService() {
            return OrderServiceFactory.createOrderService();
        }
    }
    
  6. Using annotations for factory method injection in Spring:

    • Annotate factory methods with @Bean to indicate they should be used for creating Spring beans.
    // AppConfig.java
    @Configuration
    public class AppConfig {
    
        @Bean
        public ShoppingCartService shoppingCartService() {
            return ShoppingCartFactory.createShoppingCartService();
        }
    }
    
  7. Customizing object creation with factory methods in Spring:

    • Customize object creation by implementing factory methods with specific logic.
    // CustomFactory.java
    public class CustomFactory {
    
        public static CustomService createCustomService(String config) {
            // Custom logic based on config
            return new CustomService();
        }
    }