2014-11-24 17 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> 
相关问题