Can Spring init Bean(Factory)PostProcessor lazily? - java

Could anybody explain me it? After reading the documentation I didn't understand.
Can Spring init Bean(Factory)PostProcessor lazily or not?
https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-extension-factory-postprocessors
There is a such block that confuse me:
As with BeanPostProcessors , you typically do not want to configure BeanFactoryPostProcessors for lazy initialization. If no other bean references a Bean(Factory)PostProcessor, that post-processor will not get instantiated at all. Thus, marking it for lazy initialization will be ignored, and the Bean(Factory)PostProcessor will be instantiated eagerly even if you set the default-lazy-init attribute to true on the declaration of your element.

The correct answer to the question: "Can Spring init Bean(Factory)PostProcessor lazily?" is "NO". I checked it by myself. I created 2 classes:
#Lazy
#Component
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("bean factory!");
}
}
and
#Lazy
#Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("before init!");
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
And run spring application. So, in console it was printed: "bean factory" and several times "before init", although I put #Lazy annotation on these classes.

Related

How to intercept configuration of all ThreadPoolTaskExecutors?

I'd like to intercept the creation of all ThreadPoolTaskExecutors inside the application context, and add all of them a custom TaskDecorator.
Pseudocode:
public void interceptTaskExecutors(List<ThreadPoolTaskExecutor> executors) {
var decorator = new MyTaskDecorator();
executors.stream().forEach(executor -> executor.setTaskDecorator(decorator));
}
But how can I actually intercept the bean initialization process of all TaskExecutors to apply this?
#M. Deinum probably means as follows:
#Configuration
public class ThreadPoolCustomizer implements BeanPostProcessor {
#Autowired
private TaskDecorator decorator;
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof ThreadPoolTaskExecutor)
((ThreadPoolTaskExecutor) bean).setTaskDecorator(decorator);
return bean;
}
}

Tell Spring not to invoke shutdown on beans of a specific type

On application close, each singleton bean is destroyed by DefaultListableBeanFactory.destroySingletons().
If the bean has a public void no-arg method called shutdown, then it will be invoked.
I have some 3rd party beans, all of which implement a certain interface, let's call it DoNotDestroy, that I do not want Spring to destroy.
I can specify a blank string destroy method on each bean, like so:
#Bean(destroyMethod = "")
public MyBean myBean() {
return new MyBean();
}
However, I would prefer to somehow configure Spring to not destroy any beans that implement DoNotDestroy. Is there a good way to do this?
Rather than blanking out the destroy method in each #Bean method, I can implement a BeanFactoryPostProcessor to do the same thing:
#Component
public class DoNotDestroyPostProcessor implements BeanFactoryPostProcessor {
private final Logger log = LoggerFactory.getLogger(DoNotDestroyPostProcessor.class);
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String[] doNotDestroys = beanFactory.getBeanNamesForType(DoNotDestroy.class);
for (String doNotDestroy : doNotDestroys) {
BeanDefinition bean = beanFactory.getBeanDefinition(doNotDestroy);
log.info("Don't destroy bean {} {}", bean.getFactoryMethodName(), bean.getDestroyMethodName());
bean.setDestroyMethodName("");
}
}
}
This avoids the problem of someone adding a bean and forgetting to blank out the destroy method.

Log spring Bean instantiation

How can we log each bean instantiation in Spring?
I wish to log a message every time a bean is initialized.
I have N number of bean and I don't want to put any logger on init method for each bean.
I see this as a cross-cutting concern, but not sure how to achieve this.
Is there a way.?
You can use a BeanPostProcessor
#Component
public class LogBeanPostProcessor implements BeanPostProcessor {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
LOGGER.log(String.format("Bean instantiated with name %s and class %s", beanName, bean.getClass().getSimpleName()));
return bean;
}
}
Try setting logging level of org.springframework.beans.factory to TRACE or DEBUG.
I use log4j2 with xml configuration:
<logger name="org.springframework.beans.factory" level="trace"/>
You can use Spring's event listener (explained here) to listen for event. I believe the event you need to listen to is ContextRefreshedEvent, e.g.:
#Component
public class MyListener
implements ApplicationListener<ContextRefreshedEvent> {
public void onApplicationEvent(ContextRefreshedEvent event) {
...
}
}

Invoke action after bean is created by Spring

I want to execute custom action after a Spring container will create the instance of some type of bean e.g. bean which is annotated with #MyAnnotation.
I do not want to use #PostConstructno init-method because the required custom action should not be saved in created bean but outside of it.
So I hope that Spring has some interface with method like newBeanCreated and I hope that I wolud implement it like this:
public void newBeanCreated(Object newObjReference){
if (newObjReference.getClass().isAnnotationPresent(MyAnnotation.class)) {
System.out.println("Here I am!");
}
}
I think you ar looking for the BeanPostProcessor interface.
Below example might also help you:
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("com.x.y.z")) //Fully Classified Bean Class Name
{
//You can place your logic here
}
return bean;
}
}

Getting BeanNotOfRequiredTypeException in Spring while using BeanPostProcessor

I am trying to run a Spring example using BeanPostProcessor.
Below is the bean post processor
public class DisplayNamePostProcessor implements BeanPostProcessor{
DisplayNamePostProcessor(){
System.out.println("DisplayNamePostProcessor instantiated");
}
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("postProcessBeforeInitialization for bean "+beanName);
return this;
}
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("postProcessAfterInitialization for bean "+beanName);
return this;
}
}
here, is the spring configuration file
<bean id="car" class="com.core.Car" >
<property name="wheel" value="four" />
</bean>
<bean class="com.core.DisplayNamePostProcessor"></bean>
Here, is my bean class
public class Car {
private String wheel;
public String getWheel() {
return wheel;
}
public void setWheel(String wheel) {
this.wheel = wheel;
}
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("application context loaded");
Car car = context.getBean("car", Car.class);
}
}
On running the above main method, I am getting the below exception
Exception in thread "main" org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'car' must be of type [com.core.Car], but was actually of type [com.core.DisplayNamePostProcessor]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:361)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:198)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1121)
Can someone please let me know what Ia m doing wrong and how to resolve this exception. Also, what is the root cause of it?
Any BeanPostProcessor beans you declare will be picked up by the ApplicationContext bean factory and used. Your implementation does this
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("postProcessBeforeInitialization for bean "+beanName);
return this;
}
Instead of doing anything to the target bean, it simply returns itself. It thus overrides all beans it processes with a DisplayNamePostProcessor bean.

Categories