2016-08-19 140 views
2

默認@Autowired未定義應該自動裝配的Bean時,Spring實現拋出錯誤。有沒有可能配置Spring,這將分配空對象而不是拋出異常?Spring Autowired如果未找到,則返回null

編輯:

我已經添加到required=falseAutowired但它仍然無法正常工作。 那是我的代碼:

@Autowired 
private ApplicationContext applicationContext; 

@Autowired(required = false) 
private HelloService helloService; 

public HelloController() { 
    message = "Hello World"; 
    System.out.println("Controller constructor"); 
} 

@RequestMapping(method = RequestMethod.GET) 
public ModelAndView helloWorld() { 
    ModelAndView modelAndView = new ModelAndView("hello"); 
    if (helloService == null) { 
     System.out.println(message); 
    } else { 
     helloService.hello(); 
     BeanDefinitionRegistry factory = (BeanDefinitionRegistry) applicationContext.getAutowireCapableBeanFactory(); 
     factory.removeBeanDefinition("helloService"); 
    } 
    return modelAndView; 
} 

在第一次請求它的自動連接,但與factory.removeBeanDefinition("helloService")去除豆後下一個請求,控制器豆再次施工,我得到NoSuchBeanDefinitionException

EDIT2:

我已經創建了以下機構的另一個控制器:

@Autowired(required = false) 
private TestService testService; 

@RequestMapping(method = RequestMethod.GET) 
public ModelAndView hello() { 
    ModelAndView modelAndView = new ModelAndView("hello"); 
    return modelAndView; 
} 

它正常工作 - Obj ect爲空並且不會出錯。也許我應該使用不同的方法從Spring上下文中刪除bean?

堆棧跟蹤:

org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'helloService' is defined 
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:698) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1175) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:284) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.resolvedCachedArgument(AutowiredAnnotationBeanPostProcessor.java:508) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.access$200(AutowiredAnnotationBeanPostProcessor.java:115) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:538) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
... 

重現步驟:

https://github.com/nowszy94/Autowired-null

+0

請告訴我們你的異常 – xenteros

+0

的[@Autowired可能重複的堆棧跟蹤的構造函數(必需= FALSE)給NoSuchBeanDefinitionException](http://stackoverflow.com/questions/23267440/autowiredrequired-false-on-constructor-giving-nosuchbeandefinitionexception) – xenteros

+0

我不能重現你的問題。請發佈[mcve]。 –

回答

3

問題是AutowiredAnnotationBeanPostProcessor緩存注入結果。所以,當你從上下文中刪除bean時,這個類認爲這個對象實際上是存在的(參見私有類AutowiredFieldElement在AutowiredAnnotationBeanPostProcessor.class和方法注入中擴展了InjectionMetadata.InjectedElement)。所以,你應該清除緩存。

最笨的辦法,我發現的是,但看起來像你想要做

@Controller 
@RequestMapping("/hello") 
public class HelloController { 

    @Autowired(required = false) 
    private HelloService helloService; 

    @Autowired 
    private ApplicationContext applicationContext; 

    @RequestMapping(method = RequestMethod.GET) 
    public ModelAndView modelAndView() { 
     ModelAndView modelAndView = new ModelAndView("hello"); 
     if (helloService != null) { 
      helloService.hello(); 
      removeBean("helloService"); 
     } 

     return modelAndView; 
    } 

    private void removeBean(String beanName) { 
     BeanDefinitionRegistry factory = (BeanDefinitionRegistry) applicationContext 
       .getAutowireCapableBeanFactory(); 
     factory.removeBeanDefinition(beanName); 
     clearCache(factory); 
    } 

    private void clearCache(BeanDefinitionRegistry beanFactory){ 
     AutowiredAnnotationBeanPostProcessor processor = null; 

     for (BeanPostProcessor beanPostProcessor : ((DefaultListableBeanFactory) beanFactory).getBeanPostProcessors()){ 
      if (beanPostProcessor.getClass().equals(AutowiredAnnotationBeanPostProcessor.class)){ 
       processor = (AutowiredAnnotationBeanPostProcessor) beanPostProcessor; 
      } 
     } 

     try { 
      Field injectionMetadataCache = processor.getClass().getDeclaredField("injectionMetadataCache"); 
      injectionMetadataCache.setAccessible(true); 
      Method clear = Map.class.getMethod("clear"); 
      clear.invoke(injectionMetadataCache.get(processor)); 
     } catch (NoSuchFieldException e) { 
      e.printStackTrace(); 
     } catch (NoSuchMethodException e) { 
      e.printStackTrace(); 
     } catch (IllegalAccessException e) { 
      e.printStackTrace(); 
     } catch (InvocationTargetException e) { 
      e.printStackTrace(); 
     } 


    } 

} 
+1

這個巨大的反射只是調用'processor.injectionMetadataCache.clear();'但這是私人的方法,所以用反射做到這一點 –

+0

謝謝,這是有效的。你能否在這裏發佈你的答案 - http://stackoverflow.com/questions/39043038/autowiredrequired-false-fails-after-removing-bean? – nowszy94

4

您可以通過required屬性設置爲false禁用此。

@Autowired(required=false)

如果春天找不到豆,它會離開現場未設置爲空。

+0

請參閱我的版本的問題 – nowszy94