2014-05-22 32 views
5

我怎样才能防止在我返回对象后Spring的invoiceServce的@PostConstruct方法被调用?使用Java Config时,如何防止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

我不明白:你有一个'@ Bean' problematicService(),你在那里构造一个'ProblematicService',但是你说它是“由其他代码为我构建的”。你想说你可以从API访问'ProblematicService',并且你需要构建它,但是API带有@ PostConstruct注解,你不能改变它? –

+0

是的,有问题的服务对我来说已经从我的控制之外的代码构建。 –

+0

你们每个人都打算调用'@ PostConstruct'注释的方法吗?而“ProblematicService”声明为“final”? –

回答

4

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

其实,你可以只声明CommonAnnotationBeanPostProcessor一个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; 
} 

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

我将首先建议尝试找到解决办法。例如,返回一个包装对象,它可以让您访问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方法永远不会被调用。

+0

不错的CGLib解决方案,真的很聪明! +1!但是如果ProblematicService有一些强制Spring为它创建一个JDK动态代理的事务行为会发生什么。这不会破坏CGLib实现,因为无法在JDK代理上创建CGLib代理? – geoand

+0

@geoand好点。我们必须测试CGLIB类是否可以代理。我会brb。同时,我提供了一个更清洁的解决方案。 –

+0

是的,我看到你的更新解决方案,我必须说我也喜欢它!我不得不承认,我没有意识到,声明一个类型后处理器的bean将强制Spring删除默认注册的一个。好东西!!! – geoand