4

読みました:

複数のコンポーネント スキャン

Spring MVC の ApplicationContext と WebApplicationContext の違いは何ですか?

<context:component-scan /> がディスパッチャ コンテキストではなくアプリケーション コンテキストにある場合、@RequestMapping アノテーションが機能しない(これについては後で詳しく説明します)

他にもいくつかありますが、これらのどれも質問に答えていません:

Spring MVC アプリケーションの ROOT コンテキストに存在する場合、スコープが<context:component-scan.../>制限されるのはなぜですか?

私の理解では、指定されたパッケージ内のすべてのクラスのスキャンが発生し、ステレオタイプ化された Bean@Componentまたはそのサブステレオタイプ ( @Repository@Serviceおよび@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 (サーブレット コンテキスト)

<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 が共有され、個々のサーブレット アプリケーション コンテキストで使用できると記載されています。したがって、<context:...>ルート コンテキストでの 2 つの宣言により、サーブレット コンテキストで表示される Bean が生成されます。しかし、そうではないようです。サーブレットのコンテキストで<context:component-scan.../>両方を繰り返す必要があります。<context:property-placeholder.../>

<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ステートメントが 2 つあると、コントローラー Bean が 2 回インスタンス化されることはありませんか?

<context:component-scan /> がディスパッチャ コンテキストではなくアプリケーション コンテキストにある場合、@RequestMapping アノテーションが機能しないことに関しては<mvc:annotation-driven />、アプリ コンテキストにあり、ここでの回答では 2 つのcomponent-scanステートメントが必要な理由が説明されていません。

「魔法」がどのように機能するかを完全に理解し、何かを微調整したときにどのように動作するかを予測できない限り、「魔法」を使用するのは本当に不快です。したがって、「両方の場所に追加して先に進む」という「解決策」は受け入れられません。

4

1 に答える 1

4

<context:property-placeholder />

<context:property-placeholder />レジスタはPropertySourcesPlaceholderConfigurer[ BeanFactoryPostProcessor] です。ここでの鍵はBeanFactory、それは で動作しますBeanFactory(ApplicationContextはそのようなものです)。正確には、BeanFactory定義されている上で動作します。親コンテキストまたは子コンテキストでは動作しません。したがって、両方のコンテキストで登録する必要があります。

<context:property-placeholder />2 つの同じものを使用すると、両方とも同じリソースが読み込まれ、同じプロパティ ファイルが 2 回読み込まれるという欠点が 1 つあります。これを解消するには<context:property-placeholder />、 を<util:properties />要素と組み合わせます。後者はプロパティ ファイルをロードし、それらをコンテキスト内の Bean として公開します。属性<context:property-placeholder />を使用して、この Bean を に接続できます。properties-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、親コンテキストでは定義されていません。これを実現するためにdetectHandlerMethodsInAncestorContextsプロパティを設定できます。true

経験則として、ルート コンテキストには、サービス、リポジトリ、データソースなどのインフラストラクチャ Bean などのアプリケーション グローバルをすべて含める必要があると言えDispatcherServletます@Controllers

をコピーして貼り付けるだけで<context:component-scan />、文字通り複製することは、悪い (非常に悪い) 考えです。これにより、すべての Bean が 2 回インスタンス化され、トランザクションやメモリなどの問題が発生する可能性があるため<tx:annotation-driven />です。BeanFactoryPostProcessorBeanPostProcessor

ルート コンテキスト

<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 に答える