Close

Using Spring 5 BeanDefinitionCustomizer and new methods in GenericApplicationContext to programmatically register beans

[Last Updated: Nov 5, 2025]

New methods in GenericApplicationContext

The existing class GenericApplicationContext is an implementation of ConfigurableApplicationContext interface. This class also implements BeanDefinitionRegistry interface. Typical usage of this class is to register a variety of bean definitions via the BeanDefinitionRegistry interface. In addition to the existing method registerBeanDefinition(beanName, beanDefinition), Spring 5.0 added following new convenient methods for registering beans:

package org.springframework.context.support;
 ......
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {

   //existing implementation of BeanDefinitionRegistry#registerBeanDefinition method
   @Override
   public void registerBeanDefinition(String beanName, 
                                      BeanDefinition beanDefinition) 
                                      throws BeanDefinitionStoreException {....}

   //spring 5.0 new methods
   //registering a bean by its class 
   public final <T> void registerBean(Class<T> beanClass, 
                                      BeanDefinitionCustomizer... customizers) {....}
   //registering a bean by its name and class 
   public final <T> void registerBean(@Nullable String beanName, 
                                      Class<T> beanClass,
                                      BeanDefinitionCustomizer... customizers){....}
   //following two new methods uses Java 8 Supplier which return the bean instance themselves, hence no reflection
   //involved in bean creation
   public final <T> void registerBean(Class<T> beanClass, 
                                      Supplier<T> supplier,
                                      BeanDefinitionCustomizer... customizers) {....}
   public <T> void registerBean(@Nullable String beanName,
                                Class<T> beanClass, 
                                @Nullable Supplier<T> supplier,
				BeanDefinitionCustomizer... customizers) {....}
}  

Note that all new methods' last parameter is of new Spring 5.0 interface BeanDefinitionCustomizer.

GenericApplicationContext must call AbstractApplicationContext.refresh() to initialize the registered beans.

Spring 5.0 new interface BeanDefinitionCustomizer

package org.springframework.beans.factory.config;
 ....
@FunctionalInterface
public interface BeanDefinitionCustomizer {
   //Customize the given bean definition.
   void customize(BeanDefinition bd);
}

This interface can be used as a callback for customizing a given bean definition. It is designed for use with Java 8 lambda expressions or method references. Check out previous tutorial on how to use BeanDefinition

Examples

Beans

public interface OrderService {
    void placeOrder(String item, int qty);

    public static class OrderServiceImpl implements OrderService {

        private LogService logService;

        public OrderServiceImpl() {
            System.out.printf("instance of %s created: %s%n", this.getClass().getName(),
                    System.identityHashCode(this));
        }

        public OrderServiceImpl(LogService logService) {
            this();
            this.logService = logService;
        }

        public void setLogService(LogService logService) {
            this.logService = logService;
        }

        @Override
        public void placeOrder(String item, int qty) {
            System.out.printf("placing order item: %s, qty: %s, instance: %s%n",
                    item, qty, System.identityHashCode(this));
            if (logService != null) {
                logService.log("Order placed");
            }
        }

        private void init() {
            System.out.printf("%s, init method called, instance: %s%n", this.getClass().getName(),
                    System.identityHashCode(this));
        }

        private void destroy() {
            System.out.printf("%s, destroy method called, instance: %s%n", this.getClass().getName(),
                    System.identityHashCode(this));
        }
    }
}
public interface LogService {
    void log(String msg);

    class LogServiceImpl implements LogService {
        public LogServiceImpl() {
            System.out.printf("instance of %s created: %s%n", this.getClass().getName(),
                    System.identityHashCode(this));
        }

        @Override
        public void log(String msg) {
            System.out.println(msg);
        }

        private void init() {
            System.out.printf("%s, init method called, instance: %s%n", this.getClass().getName(),
                    System.identityHashCode(this));
        }
    }
}

Using new methods of BeanDefinitionCustomizer

Not using any customizer yet:

import org.springframework.context.support.GenericApplicationContext;

public class RegisterBeanExample1 {
  //using registerBean(beanClass, customizers)
  public static void main(String[] args) {
      GenericApplicationContext gac = new GenericApplicationContext();
      gac.registerBean(OrderService.OrderServiceImpl.class);//not using customizer
      gac.refresh();
      System.out.println("context refreshed");
      OrderService os = gac.getBean(OrderService.class);
      os.placeOrder("Laptop", 2);
      System.out.println("-----------");
      //retrieving the bean one more time
      os = gac.getBean(OrderService.class);
      os.placeOrder("Desktop", 2);
      gac.close();
  }
}

Output

instance of OrderService$OrderServiceImpl created: 6688698
context refreshed
placing order item: Laptop, qty: 2, instance: 6688698
-----------
placing order item: Desktop, qty: 2, instance: 6688698

Creating customizers

We have created a util class for BeanDefinitionCustomizers, so its methods can be used as Java 8 method references:

public class Customizers {

  public static void prototypeScoped(BeanDefinition bd) {
      bd.setScope(ConfigurableBeanFactory.SCOPE_PROTOTYPE);
  }

  public static void lazy(BeanDefinition bd) {
      bd.setScope(ConfigurableBeanFactory.SCOPE_PROTOTYPE);
  }


  public static void defaultInitMethod(BeanDefinition bd) {
      bd.setInitMethodName("init");
  }

  public static void defaultDestroyMethod(BeanDefinition bd) {
      bd.setDestroyMethodName("destroy");
  }
}

Registering bean as prototype scoped bean

import org.springframework.context.support.GenericApplicationContext;

public class RegisterBeanExample2 {
  //using registerBean(beanClass, customizers)
  public static void main(String[] args) {
      GenericApplicationContext gac = new GenericApplicationContext();
      gac.registerBean(OrderService.OrderServiceImpl.class,
              Customizers::prototypeScoped);
      gac.refresh();
      System.out.println("context refreshed");
      OrderService os = gac.getBean(OrderService.class);
      os.placeOrder("Laptop", 2);
      System.out.println("-----------");
      //retrieving the bean one more time
      os = gac.getBean(OrderService.class);
      os.placeOrder("Desktop", 3);
      gac.close();
  }
}

Output

context refreshed
instance of OrderService$OrderServiceImpl created: 1579577798
placing order item: Laptop, qty: 2, instance: 1579577798
-----------
instance of OrderService$OrderServiceImpl created: 1628944913
placing order item: Desktop, qty: 3, instance: 1628944913

Registering bean by name

import org.springframework.context.support.GenericApplicationContext;

public class RegisterBeanExample3 {
  //using registerBean(beanName, beanClass, customizers)
  public static void main(String[] args) {
      GenericApplicationContext gac = new GenericApplicationContext();
      gac.registerBean("orderBean", OrderService.OrderServiceImpl.class,
              Customizers::lazy);
      gac.refresh();
      System.out.println("context refreshed");
      OrderService os = (OrderService) gac.getBean("orderBean");
      os.placeOrder("Laptop", 2);
      gac.close();
  }
}

Output

context refreshed
instance of OrderService$OrderServiceImpl created: 699448661
placing order item: Laptop, qty: 2, instance: 699448661

Using multiple BeanDefinitionCustomizers

import org.springframework.context.support.GenericApplicationContext;

public class RegisterBeanExample4 {
  //using registerBean(beanClass, beanSupplier,  customizers)
  public static void main(String[] args) {
      GenericApplicationContext gac = new GenericApplicationContext();
      gac.registerBean(LogService.class, LogService.LogServiceImpl::new,
              Customizers::lazy, Customizers::defaultInitMethod);
      gac.refresh();
      System.out.println("context refreshed");
      LogService ls = gac.getBean(LogService.class);
      ls.log("msg from main method");
      gac.close();
  }
}

Output

context refreshed
instance of LogService$LogServiceImpl created: 406266436
LogService$LogServiceImpl, init method called, instance: 406266436
msg from main method

Injecting other bean via constructor

import org.springframework.context.support.GenericApplicationContext;

public class RegisterBeanExample5 {
  //injecting other bean via constructor
  public static void main(String[] args) {
      GenericApplicationContext gac = new GenericApplicationContext();
      gac.registerBean(LogService.class, LogService.LogServiceImpl::new, Customizers::lazy,
              Customizers::defaultInitMethod);
      gac.registerBean(OrderService.OrderServiceImpl.class,
              Customizers::defaultInitMethod, Customizers::defaultDestroyMethod);
      gac.refresh();
      System.out.println("context refreshed");
      OrderService os = gac.getBean(OrderService.class);
      os.placeOrder("Laptop", 2);
      gac.close();
  }
}

Output

instance of LogService$LogServiceImpl created: 360490648
LogService$LogServiceImpl, init method called, instance: 360490648
instance of OrderService$OrderServiceImpl created: 202072331
OrderService$OrderServiceImpl, init method called, instance: 202072331
context refreshed
placing order item: Laptop, qty: 2, instance: 202072331
Order placed
OrderService$OrderServiceImpl, destroy method called, instance: 202072331

Example Project

Dependencies and Technologies Used:

  • spring-context 6.2.12 (Spring Context)
     Version Compatibility: 5.0.0.RELEASE - 6.2.12Version List
    ×

    Version compatibilities of spring-context with this example:

    • 5.0.0.RELEASE
    • 5.1.0.RELEASE
    • 5.1.1.RELEASE
    • 5.1.2.RELEASE
    • 5.1.3.RELEASE
    • 5.1.4.RELEASE
    • 5.1.5.RELEASE
    • 5.1.6.RELEASE
    • 5.1.7.RELEASE
    • 5.1.8.RELEASE
    • 5.1.9.RELEASE
    • 5.1.10.RELEASE
    • 5.1.11.RELEASE
    • 5.1.12.RELEASE
    • 5.1.13.RELEASE
    • 5.1.14.RELEASE
    • 5.1.15.RELEASE
    • 5.1.16.RELEASE
    • 5.1.17.RELEASE
    • 5.1.18.RELEASE
    • 5.1.19.RELEASE
    • 5.1.20.RELEASE
    • 5.2.0.RELEASE
    • 5.2.1.RELEASE
    • 5.2.2.RELEASE
    • 5.2.3.RELEASE
    • 5.2.4.RELEASE
    • 5.2.5.RELEASE
    • 5.2.6.RELEASE
    • 5.2.7.RELEASE
    • 5.2.8.RELEASE
    • 5.2.9.RELEASE
    • 5.2.10.RELEASE
    • 5.2.11.RELEASE
    • 5.2.12.RELEASE
    • 5.2.13.RELEASE
    • 5.2.14.RELEASE
    • 5.2.15.RELEASE
    • 5.2.16.RELEASE
    • 5.2.17.RELEASE
    • 5.2.18.RELEASE
    • 5.2.19.RELEASE
    • 5.2.20.RELEASE
    • 5.2.21.RELEASE
    • 5.2.22.RELEASE
    • 5.2.23.RELEASE
    • 5.2.24.RELEASE
    • 5.2.25.RELEASE
    • 5.3.0
    • 5.3.1
    • 5.3.2
    • 5.3.3
    • 5.3.4
    • 5.3.5
    • 5.3.6
    • 5.3.7
    • 5.3.8
    • 5.3.9
    • 5.3.10
    • 5.3.11
    • 5.3.12
    • 5.3.13
    • 5.3.14
    • 5.3.15
    • 5.3.16
    • 5.3.17
    • 5.3.18
    • 5.3.19
    • 5.3.20
    • 5.3.21
    • 5.3.22
    • 5.3.23
    • 5.3.24
    • 5.3.25
    • 5.3.26
    • 5.3.27
    • 5.3.28
    • 5.3.29
    • 5.3.30
    • 5.3.31
    • 5.3.32
    • 5.3.33
    • 5.3.34
    • 5.3.35
    • 5.3.36
    • 5.3.37
    • 5.3.38
    • 5.3.39
    • Compatible Java Version: 17+
    • 6.0.0
    • 6.0.1
    • 6.0.2
    • 6.0.3
    • 6.0.4
    • 6.0.5
    • 6.0.6
    • 6.0.7
    • 6.0.8
    • 6.0.9
    • 6.0.10
    • 6.0.11
    • 6.0.12
    • 6.0.13
    • 6.0.14
    • 6.0.15
    • 6.0.16
    • 6.0.17
    • 6.0.18
    • 6.0.19
    • 6.0.20
    • 6.0.21
    • 6.0.22
    • 6.0.23
    • 6.1.0
    • 6.1.1
    • 6.1.2
    • 6.1.3
    • 6.1.4
    • 6.1.5
    • 6.1.6
    • 6.1.7
    • 6.1.8
    • 6.1.9
    • 6.1.10
    • 6.1.11
    • 6.1.12
    • 6.1.13
    • 6.1.14
    • 6.1.15
    • 6.1.16
    • 6.1.17
    • 6.1.18
    • 6.1.19
    • 6.1.20
    • 6.1.21
    • 6.2.0
    • 6.2.1
    • 6.2.2
    • 6.2.3
    • 6.2.4
    • 6.2.5
    • 6.2.6
    • 6.2.7
    • 6.2.8
    • 6.2.9
    • 6.2.10
    • 6.2.11
    • 6.2.12

    Versions in green have been tested.

  • JDK 25
  • Maven 3.9.11

Dynamic Bean Registration using Spring 5 methods Select All Download
  • spring-5-programmatic-bean-registration
    • src
      • main
        • java
          • RegisterBeanExample4.java

    See Also