How can I prevent the @PostConstruct method on the ProblematicSerivce from being invoked by Spring after I return the object?
@Configuration
class MyConfig {
@Bean
public ProblematicService problematicService() {
ProblematicService service = someMethodOutsideMyControl();
// ProblematicService is constructed for me by other code (outside of Spring)
// and it happens to have a @PostConstruct method. The @PostConstruct method
// cannot be invoked here or by Spring once this method returns.
return service;
}
}
I believe wrapping the result in a FactoryBean would have the desired effect, but I need to repeat this code in several places, so I'm looking for a more elegant solution.
This is a non-trivial change. A @Configuration
class (or rather the AnnotationConfigApplicationContext
) registers a CommonAnnotationBeanPostProcessor
which is in charge of invoking the @PostConstruct
method of a bean. Changing that would mean changing almost the whole Spring IoC stack.
Actually, you could just declare a CommonAnnotationBeanPostProcessor
with a bean name org.springframework.context.annotation.internalCommonAnnotationProcessor
which will override the default one. You can sett the init annotation type to null
so that it ignores @PostConstruct
.
@Bean(name = "org.springframework.context.annotation.internalCommonAnnotationProcessor")
public CommonAnnotationBeanPostProcessor commonAnnotationBeanPostProcessor() {
CommonAnnotationBeanPostProcessor bean = new CommonAnnotationBeanPostProcessor();
bean.setInitAnnotationType(null);;
return bean;
}
Careful while using this as it might break other things.
I'm going to first recommend to try and find a way around that. For example, return a wrapper object which can give you access to the ProblematicService
.
@Bean
public ServiceProvider provider() {
ProblematicService service = ...;
ServiceProvider provider = new ServiceProvider(service);
return provider;
}
Or similarly the FactoryBean
you suggested.
Another, cooler, but uglier way to do it is to wrap the object in a CGLIB proxy.
@Bean
public ProblematicService service() {
ProblematicService service = ...;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(service.getClass());
enhancer.setCallback(new MethodInterceptor() {
ProblematicService inner = service;
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
if (!method.getName().equals("initMethodName"))
return method.invoke(inner, args);
return null;
}
});
return (ProblematicService) enhancer.create();
}
Basically the init-method can never be called.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With