2014-11-24 37 views
1

我已閱讀Injecting Jaxb2Marshaller in Spring MVC controllerDifference between applicationContext.xml and spring-servlet.xml in Spring Framework等,但感覺困惑,爲什麼我的情況不起作用。無法將servlet上下文中的bean注入到控制器中

以下是我在我的應用程序上下文和web.xml(下調,只顯示相關部分):

的web.xml:

<?xml version="1.0" encoding="UTF-8"?> 
<web-app .... > 

    <context-param> 
     <param-name>contextConfigLocation</param-name> 
     <param-value>classpath:/app-context.xml</param-value> 
    </context-param> 
    <listener> 
     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
    </listener> 
    .... 
    <servlet> 
     <servlet-name>spring-rest</servlet-name> 
     <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
     <load-on-startup>1</load-on-startup> 
    </servlet> 
    <servlet-mapping> 
     <servlet-name>spring-rest</servlet-name> 
     <url-pattern>/rest/*</url-pattern> 
    </servlet-mapping> 
    ... 
</web-app> 

彈簧休息-servlet.xml中

<beans ....> 

    <!-- Only scan for Controllers in Servlet context --> 
    <context:component-scan base-package="com.fil.ims" use-default-filters="false"> 
     <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> 
     <context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/> 
    </context:component-scan> 

    <mvc:annotation-driven /> 

    <context:annotation-config /> 

    <bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller"> 
     .... 
    </bean> 
</beans> 

我有一個控制器是這樣的:

@Controller 
public class FooControllerImpl implements FooController { 
    @Inject 
    @Named("jaxb2Marshaller") 
    Jaxb2Marshaller jaxb2Marshaller; 

    public void setJaxb2Marshaller(Jaxb2Marshaller jaxb2Marshaller) { 
     this.jaxb2Marshaller = jaxb2Marshaller; 
    } 
    //..... 
} 

我發現我無法在servlet上下文中注入jaxb2Marshaller(引發NoSuchBeanDefinitionException)。但是,如果我把jaxb2Marshaller放在主應用程序上下文中(app-context.xml),它可以正常注入。

我很困惑它爲什麼會發生。根據我的理解,如果我在web.xml中有ContextLoaderListener,則提供的上下文配置(app-context.xml)將用於創建頂級應用上下文,然後將調度器servlet上下文(在我的示例中爲spring-rest-servlet.xml)創建爲頂級應用上下文中的子上下文。

我不明白的是,控制器和要注入的bean(jaxb2Marshaller)都是在調度程序servlet環境下創建的,爲什麼我不能在我的FooController中注入jaxb2Marshaller? (據我所知,如果要注入的bean位於子應用上下文中,則不起作用,但在這種情況下似乎不是。)

有人可以解釋爲什麼嗎?


更新:

我做了另一個實驗(這讓我更加混亂),在我的控制器實現ApplicationContextAware,並從控制器,我做applicationContext.getBean("jaxb2Marshaller", Jaxb2Marshaller.class)。返回有效的bean(與我的理解一致)。似乎只有注射通過註釋不起作用。任何線索?

回答

0

(這個帖子一度被刪除,因爲我找到了解決辦法我自己。但是我認爲這isgood張貼在這裏我的答案作爲參考,看來我不是唯一一個面臨着類似的問題)

我的理解中應用程序上下文和豆之間的關係,其實都是正確的:

  1. 有一個根上下文
  2. 調度servlet上下文是根上下文
  3. 控制器和Jaxb2Marshaller是科瑞以下的兒童上下文編輯在servlet上下文中。

如果控制器和Jaxb2Marshaller都在同一個上下文中,爲什麼注入失敗?

答案是:在servlet上下文中使用Jaxb2Marshaller注入控制器不會失敗。失敗的消息來自另一個控制器在根上下文中。

根問題是我已經使用在根上下文的默認component-scan,爲此它會掃描具有@Service註釋的類,@Repository包括@Controller。這意味着我的控制器也在根環境中掃描和創建。一旦我將@Inject/@Autowired放入我的控制器中以注入一個應該在servlet上下文中創建的bean,它將導致錯誤,因爲根上下文中控制器的「意外複製」無法在子servlet上下文中看到該bean。

解是直接的:排除在根上下文控制器的掃描,並在servlet上下文僅掃描控制器:

根上下文的xml:

<context:component-scan base-package="com.foo"> 
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> 
</context:component-scan> 

調度上下文的xml :

<context:component-scan base-package="com.foo" use-default-filters="false"> 
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> 
</context:component-scan> 
相關問題