3

autowire@Controllerを使用してRegistrationControllerというスプリングコントローラーを作成しました。私は自分の好奇心のために、次のようにデフォルトのコンストラクターを作成し、ロガーステートメントを追加しました。

public RegistrationController() {
    logger.info("Registration Controller (Constructor) called-->"+this);
}

私が見つけたのは、ログファイルでSpring Source IDE(v2.9)でTomcatサーバー(v7)を起動したときです。次のように表示されます。

INFO: Initializing Spring root WebApplicationContext
2012-08-15 15:12:28,808 [pool-2-thread-1] INFO  com.controllers.registration.RegistrationController - Registration Controller (Constructor) called-->com.controllers.registration.RegistrationController@78c0dc2
Aug 15, 2012 3:12:28 PM org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring FrameworkServlet 'main'
2012-08-15 15:12:29,256 [pool-2-thread-1] INFO  com.controllers.registration.RegistrationController - Registration Controller (Constructor) called-->com.controllers.registration.RegistrationController@773ba8d6

RegistrationControllerはデフォルトでシングルトンオブジェクトであり、インスタンスを1つだけ作成する必要があることを理解しています。ただし、ログファイルからわかるように、2つのインスタンスが作成されています。どういうわけか、これは正しくないと思います。しかし、正確な答えはありません。

私のweb.xmlからの重要な行のいくつかは次のとおりです。

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>/WEB-INF/classes/applicationContext*.xml</param-value>
</context-param>
.
.
 <servlet>
    <servlet-name>main</servlet-name>
    <servlet-class>
        org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <load-on-startup>2</load-on-startup>
</servlet>



<servlet-mapping>
    <servlet-name>main</servlet-name>
    <url-pattern>*.htm</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>main</servlet-name>
    <url-pattern>*.jspx</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>main</servlet-name>
    <url-pattern>*.do</url-pattern>
</servlet-mapping>
   .
   .
   </web-app>

ご想像のとおり、Spring構成ファイルとしてmain-servlet.xmlとapplicationContext.xmlがあります。

ここで何が起こっているのか理解するのを手伝ってくれませんか。

8時間経過する前に質問に答えられないため、編集しました。

<context:component-scan />applicationContext.xmlとmain-servlet.xmlで検索するよう提案してくれた@Andnaに感謝します。私は両方のファイルにその要素を持っていたので、すべての春のBeanが2回スキャンされました。

ただし、<context:component-scan />applicationContext.xmlからを削除すると、Springのセキュリティ構成が壊れました。詳細を説明するために、実装したクラスを作成しましたorg.springframework.security.core.userdetails.UserDetailsService

@Service("userDetailsService") 
public class DuncanUserDetailsServiceImpl implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
}
}

このクラスをサポートするために、applicationContext-security.xml(短縮バージョン)ファイルに次のものがありました。

<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
                    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
                    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                    http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">

<beans:bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
      <beans:property name="userDetailsService" ref="userDetailsService"/>
</beans:bean>

<beans:bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
    <beans:property name="providers">
        <beans:list>
            <beans:ref local="daoAuthenticationProvider" />
        </beans:list>
    </beans:property>
</beans:bean>

<authentication-manager>
    <authentication-provider user-service-ref="userDetailsService">
        <password-encoder ref= "passwordEncoder">
            <salt-source user-property="userName"/>
        </password-encoder>
     </authentication-provider>
</authentication-manager>

<beans:bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder" />

</beans:beans>

したがって<context: component-scan />、applicationContext.xmlから削除すると、「userDetailsS​​ervice」オブジェクトインスタンスが失われ、ログファイルに大量のエラーが記録されました。

したがって、私が行ったことは、コンポーネントスキャンをそのままmain-servlet.xmlに保持することでした。

<context:component-scan base-package="com.some.org" >
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    </context:component-scan>

ただし、applicationContext.xmlの除外フィルターを使用してコンポーネントスキャンを次のように編集しました。

<context:component-scan base-package="com.bankofamerica" >
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
        <context:exclude-filter type="regex" expression="com.some.org.common.http.HTTPClient" />
    </context:component-scan>

これは私が両方のことを達成するのに役立ちました:

  1. シングルトンオブジェクトが実際にシングルトンであることを確認する
  2. Springのセキュリティが以前と同じように機能することを確認します。

素晴らしい提案をありがとうございました。

4

2 に答える 2

4

applicationContext.xmlたぶん、との両方でコンポーネントスキャンを2回実行しているmain-servlet.xmlので、Springは注釈付きクラスを2回スキャンしますか?

于 2012-08-15T19:37:53.850 に答える
1

src / main / webapp / WEB-INF/web.xmlで次の構成になりました。

<web-app xmlns=... version="2.4">
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>2</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/application-context.xml,/WEB-INF/security.xml,/WEB-INF/db.xml,/WEB-INF/services.xml</param-value>
    </context-param>

    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>sitemesh</filter-name>
        <filter-class>com.opensymphony.sitemesh.webapp.SiteMeshFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>sitemesh</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

</web-app>

Springで最も一般的な問題は、Springコンテキストの誤解だと思います。DispatcherServletを詳しく見てください。Springは、 Webコンテキストであるdispatcher-servlet.xmlを自動的に検索します。このコンテキストのBeanは、ルートコンテキストで定義されているBean(たとえば、contextConfigLocationパラメーターで指定されているBean)では使用できません。これを利用できるようにするために、多くの場合、contextConfigLocationにdispatcher-servlet.xmlを含めます。これにより、SpringがWebコンテキストを2回初期化することが論理的に発生します。次に、spring-security(global-method-security)またはcomponent-scanまたはsitemeshを構成するのは悪夢であり、構成は「不安定」になります。

于 2013-06-30T11:39:50.503 に答える