Invoke action after bean is created by Spring - java

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;
}
}

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;
}
}

Init BeanPostProcessor at a later point

I'm developing an external component for applications which contains functionality to inject Jersey Client filters into lazy-loaded clients. Ive implemented a BeanPostProcessor that does this:
public class ClientFilterInjector implements BeanPostProcessor, Ordered {
private ClientTraceInterceptor clientTraceInterceptor;
public ClientFilterInjector(ClientTraceInterceptor clientTraceInterceptor) {
this.clientTraceInterceptor = clientTraceInterceptor;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if(bean instanceof JerseyWebTarget) {
((JerseyWebTarget) bean).register(clientTraceInterceptor);
}
return bean;
}
#Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}
However, Spring Boot apparently auto-scans for BeanPostProcessor implementations regardless of whether or not they're annotated or have a bean creation method. Because of this, it screws up the order for which beans are created in the application. Is there a way to defer the instantiation of a BeanPostProcessor?
Did you try to add lazy annotation?
import org.springframework.context.annotation.Lazy;
By using this annotation it will effect on the first call but later on it will exactly the same.
public class ClientFilterInjector implements BeanPostProcessor, Ordered {
private ClientTraceInterceptor clientTraceInterceptor;
public ClientFilterInjector(ClientTraceInterceptor clientTraceInterceptor) {
this.clientTraceInterceptor = clientTraceInterceptor;
}
#Override
public Object postProcessAfterInitialization(#Lazy Object bean, String beanName) {
if(bean instanceof JerseyWebTarget) {
((JerseyWebTarget) bean).register(clientTraceInterceptor);
}
return bean;
}
#Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}
It looks like if you implement BeanProcessor in the form of an anonymous class it will not get auto-scanned in the Spring Boot application init and you can defer its instantiation whenever you want by adding it to the bean factory of the application context.
((ConfigurableApplicationContext) appContext).getBeanFactory().addBeanPostProcessor(new BeanPostProcessor() {
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof WebTarget) {
((WebTarget) bean).register(instance);
}
return bean;
}
});

Can Spring init Bean(Factory)PostProcessor lazily?

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.

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) {
...
}
}

How to configure Spring BeanPostProcessor to get invoked only for a defined set of spring managed beans

How to configure Spring BeanPostProcessor to get invoked only for a defined set of spring managed beans using xml configuration or annotation?
I doubt if you can control purely by xml configuration/annotation. You can however control it within the code of the BeanPostProcessor:
public Object postProcessBeforeInitialization(Object bean, String beanName) {
if (thisBeanIsOfConcernToMe(bean, beanName){
doPostProcessTasks()...
}
}
If this BeanProcessor is not under your control, then overriding the bean and delegating to the parent for certain custom conditions would be another way to go:
public MyBeanProcessor extends NotUnderControlBeanPostProcessor {
....
public Object postProcessBeforeInitialization(Object bean, String beanName) {
if (thisBeanIsOfConcernToMe(bean, beanName){
return super.postProcessBeforeInitialization(bean, beanName)
}else{
return bean;
}
}
}

Categories