3

MVC 用と spring-ws 用の 2 つのサーブレットを備えた Spring ベースの Web アプリケーションがあります。アプリケーションにはいくつかの Bean が使用されており、それらはアノテーションを使用して自動配線されています。アプリケーションが起動するたびに、シングルトン スコープであっても、各 Bean タイプの 3 つのインスタンスが作成されます。@PostConstruct メソッドも、それぞれに対して 3 回呼び出されます。

3つのアプリケーションコンテキスト=1つの共通+2つのサーブレットがあることを理解していますが、各Bean、コントローラー、エンドポイントなどは3回作成されます。少なくとも、親アプリケーション コンテキストにロードされた共通 Bean は、1 回だけインスタンス化する必要があります。

component-scan の base-package 属性は、ばらばらのパッケージを指します。

クラスを使用してコンテキスト情報 (https://gist.github.com/1347171) をダンプしましたが、同じ構造 (同じ Bean) を持つ 3 つの異なるコンテキストがあるようです。それらの ID は「/project/」、「/project/rest」、「/project/soap」です。

ContextLoaderListener をコメントアウトして、soap サーブレットとそれに関連する XML ファイル (applicationContext と soap-servlet) を削除し、共通のものを残りのサーブレットに移動してみました (構成 xml とコンポーネントスキャンが 1 つだけになるように)。私はまだ各 Bean の 3 つのインスタンスを取得します。この場合、アプリケーション コンテキスト ID は "/Project/" (正確な大文字と小文字の区別)、"/project/"、および "/project/" です。

web.xml

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>

<servlet>
    <servlet-name>rest</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>rest</servlet-name>
    <url-pattern>/rest/*</url-pattern>
</servlet-mapping>

<servlet>
    <servlet-name>soap</servlet-name>
    <servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
    <init-param>
        <param-name>transformWsdlLocations</param-name>
        <param-value>true</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>soap</servlet-name>
    <url-pattern>/soap/*</url-pattern>
</servlet-mapping>

applicationContext.xml

<context:annotation-config/>
<context:component-scan base-package="test.common"/>

<task:annotation-driven/>

rest-servlet.xml

<mvc:annotation-driven/>
<context:component-scan base-package="test.rest"/>

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    <property name="messageConverters">
        <util:list id="beanList">
            <ref bean="formHttpMessageConverter"/>
        </util:list>
    </property>
</bean>

<bean id="formHttpMessageConverter"
      class="org.springframework.http.converter.FormHttpMessageConverter"/>

<mvc:interceptors>
    <bean class="test.rest.Interceptor"/>
</mvc:interceptors>

soap-servlet.xml

<sws:annotation-driven/>
<context:component-scan base-package="test.soap"/>

<sws:dynamic-wsdl
        id="service"
        portTypeName="service"
        locationUri="/soap/service"
        targetNamespace="http://server/soap">

    <sws:xsd location="/WEB-INF/SoapService.xsd"/>
</sws:dynamic-wsdl>

<sws:interceptors>
    <bean id="validatingInterceptor"
          class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
        <property name="schema" value="/WEB-INF/SoapService.xsd"/>
        <property name="validateRequest" value="true"/>
        <property name="validateResponse" value="true"/>
    </bean>
</sws:interceptors>
4

2 に答える 2

0

Bean で javax.ejb.Singleton アノテーションを使用します。

于 2012-10-12T06:02:13.223 に答える
0

その理由は、Spring MVC コンテキストの初期化とこれらの魔法の注釈のデフォルトに関する少し紛らわしいドキュメントです :(.

次の理由により、おそらく 3 つのコピーがあります。

  1. contextConfigLocation 定義は、すべてのサーブレットで共有されるルート webapp コンテキスト ロード (アプリケーションごとに 1 つだけ) を作成します。各 -servlet-config.xml ファイルはこれらの Bean にアクセスできますが、その逆はできません。 Spring Framework の applicationContext.xml と spring-servlet.xml の違い
  2. したがって、アノテーション駆動型を明示的に再度定義したため、2 番目のインスタンスは -servlet アプリケーション コンテキストから取得されます。
  3. 使用しているSpringフレームワークのバージョンはわかりませんが、アノテーション駆動型とカスタムリクエストマッピングアダプターの両方を定義することで、ほとんど2つを作成しています. https://jira.spring.io/browse/SPR-8648

実際、<mvc:annotation-driven>アダプターをカスタマイズするためのすべてのタグがあり、必要なスキーマを確認してください。これを理解するもう 1 つの方法は、トレース モードで面倒なデバッグを行い、どの Bean が実際にアダプターを作成しているかを調べることです。アダプター コンストラクターにブレークポイントを配置し、DispatcherServlet->mapperHandler->interceptor->mapping->context->configFileLocation のスタックを見て、この Bean を作成しているファイルを確認します

メッセージ コンバーターをカスタマイズする場合は、次のようにする必要があります。

<mvc:annotation-driven
        content-negotiation-manager="contentNegotiationManager">
            <mvc:message-converters register-defaults="false">
                <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                    <property name="objectMapper" ref="afterBurnerObjectMapper"/>
                </bean>
                <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
                <bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"/>
                <bean class="org.springframework.http.converter.FormHttpMessageConverter"/>
                <bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
            </mvc:message-converters>
    </mvc:annotation-driven>  
于 2015-10-19T01:39:12.370 に答える