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();
}
}Outputinstance 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();
}
}Outputcontext 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();
}
}Outputcontext 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();
}
}Outputcontext 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();
}
}Outputinstance 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 ProjectDependencies and Technologies Used: - spring-context 6.2.12 (Spring Context)
Version Compatibility: 5.0.0.RELEASE - 6.2.12 Version compatibilities of spring-context with this example: Versions in green have been tested.
- JDK 25
- Maven 3.9.11
|