美文网首页
spring bean标注了Autowired注解的属性没有自动

spring bean标注了Autowired注解的属性没有自动

作者: 6087cdb13f7f | 来源:发表于2017-07-03 19:40 被阅读0次

    1、问题描述

    某些spring 托管的bean,被标注Autowired注解的属性,没有自动注入对象。比如下面这个类。

    
    /**
    
    * Created by zhengwei on 2017/6/21.
    
    */
    
    @Component
    
    public classGetProductByProductIdRequestHandlerextendsPcRequestHandler {
    
    @Autowired
    
    privateProductQueryManagerproductQueryManager;
    
    @Override
    
    protectedGetProductByProductIdResponsedoHandle(GetProductByProductIdRequest request) {
    
    GetProductByProductIdResponse response =newGetProductByProductIdResponse();
    
    ProductDO product;
    
    try{
    
    product =this.productQueryManager.getProductBaseInfoById(request.getProductId());
    
    }catch(Exception e) {
    
    logger.error("getProductBaseInfoById error, productId="+ request.getProductId(),e);
    
    response.setSuccess(false);
    
    response.setResultCode(BizErrorCode.COMMON_ERROR.getErrorCode());
    
    response.setResultMsg(BizErrorCode.COMMON_ERROR.getErrorMsg());
    
    returnresponse;
    
    }
    
    response.setProduct(product);
    
    response.setSuccess(true);
    
    returnresponse;
    
    }
    
    @Override
    
    publicClasssupportRequest() {
    
    returnGetProductByProductIdRequest.class;
    
    }
    
    }
    
    

    运行的过程中,上图GetProductByProductIdRequestHandler中的属性productQueryManager为null,导致空指针异常。

    2、问题产生原因

    项目启用了配置中心,通过PropertyPlaceholderConfigurer实现,因此它是个BeanFactoryPostProcessor,而此bean在初始化spring时,会去配置中心获取配置项到本地内存,其中该bean初始化过程中,有这么一段代码,如下图:

    
    private void initListener(PropertiesConfiguration config) {
    
    Map listeners = applicationContext.getBeansOfType(MessageConfCenterListener.class);
    
    if (listeners == null) {
    
    listeners = new HashMap();
    
    }
    
    // add default contextPropertiesListener
    
    listeners.put("contextPropertiesListener", new MessageConfCenterListener() {
    
    @Override
    
    public void notifyEvent(ConfigurationEvent event) {
    
    switch (event.getType()) {
    
    case ADD:
    
    case UPDATE:
    
    contextProperties.put(event.getPropertyName(), event.getPropertyValue());
    
    break;
    
    case CLEAR:
    
    contextProperties.remove(event.getPropertyName());
    
    }
    
    }
    
    });
    
    config.addConfigurationListener(new MessageConfigurationListener(listeners.values()));
    
    }
    
    

    可以看到其中第2行代码是,

    Map listeners = applicationContext.getBeansOfType(MessageConfCenterListener.class);
    

    也就是从applicationContext获取MessageConfCenterListener,getBeansOfType此方法是根据name遍历整个bean factory里的bean,如果是FactoryBean的话,会先创建此bean,问题就出在这里了。这里需要看看AbstractApplicationContext里的refresh方法,如下图:

    
    @Override
    
    public void refresh() throws BeansException, IllegalStateException {
    
    synchronized (this.startupShutdownMonitor) {
    
    // Prepare this context for refreshing.
    
    prepareRefresh();
    
    // Tell the subclass to refresh the internal bean factory.
    
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
    // Prepare the bean factory for use in this context.
    
    prepareBeanFactory(beanFactory);
    
    try {
    
    // Allows post-processing of the bean factory in context subclasses.
    
    postProcessBeanFactory(beanFactory);
    
    // Invoke factory processors registered as beans in the context.
    
    invokeBeanFactoryPostProcessors(beanFactory);
    
    // Register bean processors that intercept bean creation.
    
    registerBeanPostProcessors(beanFactory);
    
    // Initialize message source for this context.
    
    initMessageSource();
    
    // Initialize event multicaster for this context.
    
    initApplicationEventMulticaster();
    
    // Initialize other special beans in specific context subclasses.
    
    onRefresh();
    
    // Check for listener beans and register them.
    
    registerListeners();
    
    // Instantiate all remaining (non-lazy-init) singletons.
    
    finishBeanFactoryInitialization(beanFactory);
    
    // Last step: publish corresponding event.
    
    finishRefresh();
    
    }
    
    catch (BeansException ex) {
    
    if (logger.isWarnEnabled()) {
    
    logger.warn("Exception encountered during context initialization - " +
    
    "cancelling refresh attempt: " + ex);
    
    }
    
    // Destroy already created singletons to avoid dangling resources.
    
    destroyBeans();
    
    // Reset 'active' flag.
    
    cancelRefresh(ex);
    
    // Propagate exception to caller.
    
    throw ex;
    
    }
    
    finally {
    
    // Reset common introspection caches in Spring's core, since we
    
    // might not ever need metadata for singleton beans anymore...
    
    resetCommonCaches();
    
    }
    
    }
    
    }
    
    

    1、prepareBeanFactory(beanFactory)方法,表示准备动作,初始化一些默认的配置。

    2、invokeBeanFactoryPostProcessors(beanFactory),执行BeanFactoryPostProcessor,而我们的配置中心是通过PropertyPlaceholderConfigurer来实现的,而PropertyPlaceholderConfigurer是一个BeanFactoryPostProcessor,因此这个时候会被执行。

    3、registerBeanPostProcessors(beanFactory),注册BeanPostProcessor,这个BeanPostProcessor干啥的呢,spring的Autowired注解就是通过AutowiredAnnotationBeanPostProcessor来实现的。

    因此当执行BeanFactoryPostProcessor的时候,spring还没有往容器里注册AutowiredAnnotationBeanPostProcessor,问题就这么发生了。

    相关文章

      网友评论

          本文标题:spring bean标注了Autowired注解的属性没有自动

          本文链接:https://www.haomeiwen.com/subject/oquzcxtx.html