4

我读过了:

多组件扫描

Spring MVC 中的 ApplicationContext 和 WebApplicationContext 有什么区别?

如果 <context:component-scan /> 在应用程序上下文而不是调度程序上下文中,@RequestMapping 注释不起作用(稍后会详细介绍)

和其他几个,但这些都没有回答这个问题:

<context:component-scan.../>当 Spring MVC 应用程序的 ROOT 上下文中存在时,为什么范围是有限的?

我的理解是,它会导致扫描指定包中的所有类,并实例化任何使用其原型@Component或其任何子原型(@Repository@Service)的 bean @Controller

鉴于:

applicationContext.xml(根上下文)

<beans...>
    ...
    <context:component-scan base-package="com.myproject"/>
    <context:property-placeholder 
               ignore-resource-not-found="true" 
               location="classpath:default.properties, file:///etc/gallery/gallery.properties"/>
</beans>

main-servlet.xml(servlet 上下文)

<beans ...>
    ...
    <mvc:annotation-driven/>
    <mvc:resources mapping="/image/**"   location="file:/${gallery.location}" />
    <mvc:resources mapping="/css/**"     location="/css/"/>
    <mvc:resources mapping="/js/**"      location="/js/"/>
    <mvc:resources mapping="/images/**"  location="/images/"/>
    ...
</beans>

com/myproject/web/MainController.java

package com.myproject.web;
@Controller
public class MainController 
{
    ...

    @RequestMapping("/gallery/**")
    public String gallery(ModelMap modelMap, HttpServletRequest req, HttpServletResponse resp) throws IOException
    {
        ...
    }
}

Spring 文档声明在根上下文中实例化的任何 bean 都是共享的,并且可用于各个 servlet 应用程序上下文。因此,根上下文中的两个<context:...>声明应该导致在 servlet 上下文中可见的 bean。但情况似乎并非如此。我需要在 servlet 上下文中<context:component-scan.../>重复。<context:property-placeholder.../>

在 servlet 上下文中省略 会<context:component-scan.../>导致

Sep 15, 2015 10:08:16 AM org.springframework.web.servlet.PageNotFound noHandlerFound
WARNING: No mapping found for HTTP request with URI [/gallery/habitat/20150813] in DispatcherServlet with name 'main'
Sep 15, 2015 10:08:16 AM org.springframework.web.servlet.PageNotFound noHandlerFound
WARNING: No mapping found for HTTP request with URI [/error] in DispatcherServlet with name 'main'

表示@Controller未解决。

使用未处理的属性引用省略注释中的<context:property-placeholder.../>结果@Value,在我的情况下会导致一些断开的链接。

由于这两个<context:.../>指令都会导致 bean 实例化,我很困惑为什么 bean 在子上下文中不可见,这与文档直接矛盾。此外,没有两个component-scan语句会导致控制器 bean 被实例化两次吗?

关于@RequestMapping 注释不起作用,如果 <context:component-scan /> 在应用程序上下文而不是调度程序上下文中,我确实<mvc:annotation-driven />在我的应用程序上下文中,并且这里的答案没有解释为什么component-scan需要两个语句。

除非我完全理解它是如何工作的并且可以预测当我调整某些东西时它会如何表现,否则我对使用“魔法”感到非常不舒服。所以“两个地方都加就继续”的“解决方案”是不能接受的。

4

1 回答 1

4

<context:property-placeholder />

<context:property-placeholder />寄存器 a是PropertySourcesPlaceholderConfigurer[ BeanFactoryPostProcessor]。这里的关键是BeanFactory,它在 a 上运行BeanFactoryApplicationContext就是这样的东西)。准确地说,它在BeanFactory它被定义的地方运行。而不是在父或子上下文中。因此,您需要在两种情况下都注册它。

有两个相同的<context:property-placeholder />两个将加载相同的资源有一个缺点,并且您最终会加载相同的属性文件两次。为了消除这种情况,将<context:property-placeholder /><util:properties />元素结合起来。后者加载属性文件并将它们作为 bean 在上下文中公开,您可以将此 bean 连接到<context:property-placeholder />usingproperties-ref属性。您只在根上下文中加载属性,并在子上下文中简单地引用它们。

根上下文

<util:properties id="appProperties" location="classpath:default.properties, file:///etc/gallery/gallery.properties" ignore-resource-not-found="true" />
<context:property-placeholder properties-ref="appProperties" />

子上下文

<context:property-placeholder properties-ref="appProperties" />

<mvc:annotation-driven />

关于<mvc:annotation-driven />注册的,其中包括 a RequestMappingHandlerMapper,这个 bean 负责检测在带注释的类@RequestMapping中注释的方法。@Controller默认情况下,ApplicationContext它在 NOT 在父上下文中定义的情况下执行此操作。您可以设置detectHandlerMethodsInAncestorContexts属性来true实现这一点。

根据经验,您可以说您的根上下文应该包含应用程序全局的所有内容,例如服务、存储库、基础设施 bean,例如数据源等。子上下文(由 加载的DispatcherServlet应该只包含与 Web 相关的材料,例如@Controllers.)。

只是复制粘贴<context:component-scan />,从字面上复制它,是一个坏(非常坏)的主意。因为这将导致两次实例化所有 bean,并可能导致事务、内存等问题。因为<tx:annotation-driven />使用 AOP 和 AOP 之类的东西也使用 aBeanFactoryPostProcessorBeanPostProcessor属性支持来应用。

根上下文

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

子上下文

<context:component-scan base-package="com.myproject" use-default-filters="false">
    <context:include-filters type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
于 2015-09-15T19:08:15.493 回答