Spring allows us to make a lot of operations with beans. We can decide if they should be unique instance on container (singleton) or not (prototype). We can also make some of operations "in the fly", thanks to bean factory post processors.
Data Engineering Design Patterns

Looking for a book that defines and solves most common data engineering problems? I'm currently writing
one on that topic and the first chapters are already available in 👉
Early Release on the O'Reilly platform
I also help solve your data engineering problems 👉 contact@waitingforcode.com 📩
In this short article we'll present the idea of bean factory post processors. In its first part, we'll discover what is hidden behind this concept. After we'll write some of illustration code to understand this idea better.
What are bean factory post processors in Spring ?
Sometimes we can need to implement some of dynamic behavior in our Spring applications. For example, imagine following scenario: in your site you want to display two texts, depending on day hour. On AM hours, you will display "Good morning". After, the displayed text will be "Good afternoon". In additionally, you have two daily deploys, on at 12 AM and the other at 12 PM. And don't forget that this text is must handled by one bean. We have now two choices: change application context file at every deploy or define a bean implementing org.springframework.beans.factory.config.BeanFactoryPostProcessor interface. The second solution is more elegant because we can write the code once and "forget" that it exists.
So, what is this elegant BeanFactoryPostProcessor ? It's an interface implemented by the beans which want to modify the definitions of other beans. Note that only the definitions can be modified, i.e. constructor arguments, property values. BeanFactoryPostProcessor beans are invoked before initialization of "normal" beans and it's the reason why only the meta data can be changed. The invocation is made through protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) of org.springframework.context.support.AbstractApplicationContext:
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); }
Inside PostProcessorRegistrationDelegate, the method in charge of bean factory post processors execution, is:
private static void invokeBeanFactoryPostProcessors(Collection extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) { for (BeanFactoryPostProcessor postProcessor : postProcessors) { postProcessor.postProcessBeanFactory(beanFactory); } }
As you can guess after previous code, the main method to override by BeanFactoryPostProcessor implementations is postProcessBeanFactory. Is the place where the customization of beans definition can be made. The customization is made on org.springframework.beans.factory.config.BeanDefinition objects. As already written in the article about singleton and prototype beans in Spring Framework, they contain a lot of information about beans meta data: constructor arguments, property values or scope.
Sample of bean factory post processors in Spring
All important theoretical points were described in the previous part. In this part we'll focus on more pragmatic case. Do you remember the case of "Good morning" and "Good afternoon" from the first part ? If not, go back to it and come here after the reading. If yes, let's try to implement this case in the code. First, we'll define some beans inside configuration file:
The first bean represents this one which will implement BeanFactoryPostProcessor interface. The second bean is the injected class which will display welcome text in the page. They are the codes of both beans:
// Welcomer.java public class Welcomer { private String welcomeText; public void initWelcomer() { LOGGER.debug("Welcomer is initialized"); } public void setWelcomeText(String welcomeText) { LOGGER.debug("Setting welcomeText to: "+welcomeText); this.welcomeText = welcomeText; } public String getWelcomeText() { return this.welcomeText; } @Override public String toString() { return "Welcomer {text: "+this.welcomeText+"}"; } } // BeanModifier.java public class BeanModifier implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { try { Calendar calendar = Calendar.getInstance(); if (calendar.get(Calendar.AM_PM) == Calendar.PM) { BeanDefinition welcomerDef = beanFactory.getBeanDefinition("welcomerBean"); welcomerDef.getPropertyValues().add("welcomeText", "Good afternoon"); } } catch (Exception e) { LOGGER.error("An error occurred on setting welcomeText", e); } } } // test method ApplicationContext context = new FileSystemXmlApplicationContext("/home/bartosz/webapp/src/main/resources/META-INF/applicationContext.xml"); Welcomer welcomer = (Welcomer) context.getBean("welcomer"); System.out.println("Text: "+welcomer.getWelcomeText());
Your logger file should print:
Setting welcomeText to: Good afternoon Welcomer is initialized Text: Good afternoon
As you can see here, BeanModifier is called before the real initialization of Welcomer. Thanks to overridden postProcessBeanFactory method, we can check the day time programatically and set the right value for the property "welcomeText".
The article is short but it describes an utility that you can need in some "dynamic" scenarios. For example, you can have a game in your site where every application deploy will add some bonus points to the best users. Thanks to BeanFactoryPostProcessor beans, this treatment can be done automatically inside a Java method and not manually at every deploy.
Consulting

With nearly 16 years of experience, including 8 as data engineer, I offer expert consulting to design and optimize scalable data solutions.
As an O’Reilly author, Data+AI Summit speaker, and blogger, I bring cutting-edge insights to modernize infrastructure, build robust pipelines, and
drive data-driven decision-making. Let's transform your data challenges into opportunities—reach out to elevate your data engineering game today!
👉 contact@waitingforcode.com
đź”— past projects