Close

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

[Last Updated: Feb 13, 2026]

Spring 5 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

Definition of BeanDefinitionCustomizer

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

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: 157090513
LogService$LogServiceImpl, init method called, instance: 157090513
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: 2099757575
LogService$LogServiceImpl, init method called, instance: 2099757575
instance of OrderService$OrderServiceImpl created: 1966723992
OrderService$OrderServiceImpl, init method called, instance: 1966723992
context refreshed
placing order item: Laptop, qty: 2, instance: 1966723992
Order placed
OrderService$OrderServiceImpl, destroy method called, instance: 1966723992

Example Project

Dependencies and Technologies Used:

  • spring-context 7.0.3 (Spring Context)
     Version Compatibility: 5.0.0.RELEASE - 7.0.3Version 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
    • 6.2.13
    • 6.2.14
    • 6.2.15
    • 7.0.0
    • 7.0.1
    • 7.0.2
    • 7.0.3

    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

    Join