Spring BeanFactoryPostProcessor和生命周期问题

时间:2016-04-13 19:27:48

标签: java spring spring-mvc dependency-injection

我有一个在大量服务器上运行的Spring MVC应用程序(3.2.9),它无法部署到今天这些服务器的一部分,出现自动布线问题,没有类型错误的匹配bean。这个问题在本地开发环境中是不可重复的。

该应用程序使用了很多注释,例如@ Configuration,@ Bean,@ Autowired,@ Service等

添加了一个新的@Configuration类和@Bean方法,并将Bean注入到使用@Service注释的类的构造函数中。回滚到以前版本的代码工作正常,所以看起来新的@Configuration类似乎没有被处理。这是一个奇怪的问题。我想避免在制作上重复表演 - 所以想了解发生了什么

这个问题可能是与Bean类的Spring API中记录的BeanFactoryPostProcessor生命周期问题相关的竞争条件 - 如下所述(应用程序使用PropertyPlaceholderConfigurer但它尚未配置为静态方法)?

    No qualifying bean of type [..removed...] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [..removed...] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
    org.springframework.beans.factory.support.ConstructorResolver in createArgumentArray at line 752application
    org.springframework.beans.factory.support.ConstructorResolver in autowireConstructor at line 193application
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory in autowireConstructor at line 1075application
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory in createBeanInstance at line 979application
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory in doCreateBean at line 487application
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory in createBean at line 458application
    org.springframework.beans.factory.support.AbstractBeanFactory$1 in getObject at line 296application
    org.springframework.beans.factory.support.DefaultSingletonBeanRegistry in getSingleton at line 223application
    org.springframework.beans.factory.support.AbstractBeanFactory in doGetBean at line 293application
    org.springframework.beans.factory.support.AbstractBeanFactory in getBean at line 194application
    org.springframework.beans.factory.support.DefaultListableBeanFactory in preInstantiateSingletons at line 633application
    org.springframework.context.support.AbstractApplicationContext in finishBeanFactoryInitialization at line 932application
    org.springframework.context.support.AbstractApplicationContext in refresh at line 479application
    org.springframework.web.context.ContextLoader in configureAndRefreshWebApplicationContext at line 410application
    org.springframework.web.context.ContextLoader in initWebApplicationContext at line 306application
    org.springframework.web.context.ContextLoaderListener in contextInitialized at line 112application
    org.apache.catalina.core.StandardContext in listenerStart at line 4994application
    org.apache.catalina.core.StandardContext in startInternal at line 5492application
    org.apache.catalina.util.LifecycleBase in start at line 150application
    org.apache.catalina.core.ContainerBase in addChildInternal at line 901application
    org.apache.catalina.core.ContainerBase in addChild at line 877application
    org.apache.catalina.core.StandardHost in addChild at line 649application
    org.apache.catalina.startup.HostConfig in deployWAR at line 1083application
    org.apache.catalina.startup.HostConfig$DeployWar in run at line 1879application

来自Bean类的Spring文档......

  

必须特别考虑返回Spring BeanFactoryPostProcessor(BFPP)类型的@Bean方法。由于BFPP对象必须在容器生命周期的早期实例化,因此它们可能会干扰@Configuration类中@Autowired,@ Value和@PostConstruct等注释的处理。要避免这些生命周期问题,请将BFPP返回@Bean方法标记为静态。例如:

 @Bean
 public static PropertyPlaceholderConfigurer ppc() {
     // instantiate, configure and return ppc ...
 }
  

通过将此方法标记为静态,可以调用它而不会导致其声明@Configuration类的实例化,从而避免上述生命周期冲突。但请注意,如上所述,静态@Bean方法不会针对作用域和AOP语义进行增强。这在BFPP案例中有效,因为它们通常不被其他@Bean方法引用。提醒一下,将为任何具有可分配给BeanFactoryPostProcessor的返回类型的非静态@Bean方法发出WARN级别的日志消息。

好的,一个更新,有116个服务器,并且由于某种原因,bean只在67上创建。对以下内容进行了更改并没有做太多不同的

public static PropertyPlaceholderConfigurer ppc()

@Configuration
public class BlahClientConfig {

    @Bean
    public BlahClient blahClient() throws URISyntaxException {
        try {
            BlahClientFactory factory = new BlahClientFactory();
            return factory.create();
        } catch (Exception e) {
            LOGGER.error("Failed to create blahClient",e);
            throw e;
        }
    }
}

多个组件扫描条目是否可能导致问题(遗留代码)

<context:component-scan base-package="com.blah.a.b.c"/>
<context:component-scan base-package="com.blah.d.e.f"/>
<bean class="com.blah.config.MetricsConfig"/>
<context:component-scan base-package="com.blah.a.h.config"/>
<context:component-scan base-package="com.blah.a"/>
<context:component-scan base-package="com.blah.f.g.h.i"/>
<context:component-scan base-package="
    com.blah.core.common,
    com.blah.core.domain,
    com.blah.core.shared,
    com.blah.core.spec.impl.legacy,
    com.blah.api.client.impl,
    com.blah.common.util.time"/>
<context:annotation-config/>

有人有任何线索吗?

0 个答案:

没有答案