如何在返回对象后阻止有问题的服务器上的@PostConstruct方法被Spring调用?
@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;
}
}
我相信将结果包装在FactoryBean中会产生预期的效果,但我需要在几个地方重复这段代码,所以我正在寻找更优雅的解决方案。
答案 0 :(得分:4)
这是一个非平凡的变化。 @Configuration
类(或更确切地说是AnnotationConfigApplicationContext
)注册一个CommonAnnotationBeanPostProcessor
,它负责调用bean的@PostConstruct
方法。改变这意味着几乎改变整个Spring IoC堆栈。
实际上,您只需声明一个名为CommonAnnotationBeanPostProcessor
的{{1}},它将覆盖默认名称org.springframework.context.annotation.internalCommonAnnotationProcessor
。您可以将init注释类型设置为null
,以便忽略@PostConstruct
。
@Bean(name = "org.springframework.context.annotation.internalCommonAnnotationProcessor")
public CommonAnnotationBeanPostProcessor commonAnnotationBeanPostProcessor() {
CommonAnnotationBeanPostProcessor bean = new CommonAnnotationBeanPostProcessor();
bean.setInitAnnotationType(null);;
return bean;
}
使用它时要小心,因为它可能会破坏其他东西。
我将首先建议尝试找到解决方法。例如,返回一个包装器对象,该对象可以让您访问ProblematicService
。
@Bean
public ServiceProvider provider() {
ProblematicService service = ...;
ServiceProvider provider = new ServiceProvider(service);
return provider;
}
或者类似于您建议的FactoryBean
。
另一个更酷但更丑陋的方法是将对象包装在CGLIB代理中。
@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();
}
基本上,永远不能调用init方法。