我已阅读Injecting Jaxb2Marshaller in Spring MVC controller和Difference between applicationContext.xml and spring-servlet.xml in Spring Framework等,但对我的案例不起作用感到困惑。
以下是我在app环境和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(app-context.xml
)中,则可以正常注入。
我很困惑为什么会这样。根据我的理解,如果ContextLoaderListener
中有web.xml
,则提供的上下文配置(app-context.xml)将用于创建顶级应用程序上下文,然后用于调度程序servlet上下文({我的示例中的{1}}将在顶级应用程序上下文中创建为子上下文。
我不明白的是,控制器和要注入的bean(jaxb2Marshaller)都是在调度程序servlet上下文中创建的,为什么我不能将spring-rest-servlet.xml
注入我的jaxb2Marshaller
? (我知道如果要注入的bean位于子应用程序上下文中,它将不起作用,但在这种情况下似乎不是。)
有人可以解释原因吗?
更新
我做了另一个实验(这让我更加困惑),通过在我的控制器中实现FooController
,从控制器,我做ApplicationContextAware
。返回一个有效的bean(与我的理解一致)。似乎只通过注释注入不起作用。有线索吗?
答案 0 :(得分:0)
(这篇文章曾被删除,因为我自己找到了解决方案。不过我认为很好地将我的答案发布在这里供参考,似乎我不是唯一面临类似问题的人)
我对应用程序上下文和bean之间关系的理解实际上是正确的:
如果Controllers和Jaxb2Marshaller都在同一个上下文中,为什么注入失败?
答案是:在servlet上下文中使用Jaxb2Marshaller注入控制器不会失败。失败的消息来自根上下文中的另一个控制器。
根问题是我在根上下文中使用了默认的component-scan
,它将扫描注释了@Service
,@Repository
等的类,包括 @Controller
。这意味着我的控制器也会在根上下文中进行扫描和创建。一旦我将@Inject
/ @Autowired
放入我的控制器中以注入一个应该在servlet上下文中创建的bean,它将导致错误,因为根上下文中控制器的“意外复制”无法看到bean在子servlet上下文中。
解决方案很简单:在根上下文中排除Controller的扫描,并在servlet上下文中仅扫描Controller:
root context 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>