使用Java Config时如何防止Spring生命周期方法?

Ed *_*mas 5 java spring spring-java-config

在返回对象后,如何防止问题服务器上的@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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我相信将结果包装在FactoryBean中会产生预期的效果,但我需要在几个地方重复这段代码,所以我正在寻找更优雅的解决方案.

Sot*_*lis 4

这是一个不平凡的改变。一个@Configuration类(或者更确切地说是AnnotationConfigApplicationContext)注册一个CommonAnnotationBeanPostProcessor负责调用@PostConstructbean 方法的类。改变这一点意味着改变几乎整个 Spring IoC 堆栈。

实际上,您可以只声明一个CommonAnnotationBeanPostProcessor带有 bean 名称的 bean 名称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;
}
Run Code Online (Sandbox Code Playgroud)

使用时要小心,因为它可能会破坏其他东西。

我首先建议尝试找到解决方法。例如,返回一个包装对象,它可以让您访问ProblematicService.

@Bean
public ServiceProvider provider() {
    ProblematicService service = ...;
    ServiceProvider provider = new ServiceProvider(service);
    return provider;
}
Run Code Online (Sandbox Code Playgroud)

或者类似的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();
}
Run Code Online (Sandbox Code Playgroud)

基本上 init 方法永远不会被调用。