web-dev-qa-db-ja.com

親コンテキストと子コンテキストでのSpring Beanの宣言

次のxmlを介してServletContextでインスタンス化するSpring Bean(dao)オブジェクトがあります。

<bean id="userDao" class="com.company.dao.impl.UserDaoImpl">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

このBeanは、webapp-servlet.xmlファイル内で宣言され、ServletContext内のアプリによって使用されます。

SpringSecurityも使用しています。これが別のコンテキスト(SecurityContext)で実行されることは私の理解です。

私のアプリケーションには、カスタム認証プロバイダーをインスタンス化するwebapp-security.xmlがあります。私のアプリで使用されているdaoを使用して、セキュリティコンテキストでユーザールックアップも行いたいのですが、実行すると:

<bean id="userAuthenticationProvider" class="com.company.security.UserAuthenticationProvider">
    <property name="userDao" ref="userDao" />
</bean>

そのようなBean "userDao"がないというエラーが表示されます。 Beanは、他のコンテキストで宣言されたBeanでは正常に自動配線されますが、セキュリティコンテキスト内ではありません。 Spring Docsによると、web.xmlでは両方の個別のコンテキストが必要だと思います

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

<listener>
    <listener-class>
        org.springframework.security.web.session.HttpSessionEventPublisher
    </listener-class>
</listener>

だから私の質問は、SecurityContext内のServletContextにあるDAOにアクセスするにはどうすればよいですか?私のdaoにスコープ修飾子はありますか、または認証プロバイダー内の実行時になんとかしてServletContextを取得できますか?参考までに、これは私の認証プロバイダー内で使用する方法です。

public class UserAuthenticationProvider extends
    AbstractUserDetailsAuthenticationProvider {

    @Override
protected UserDetails retrieveUser(String userName,
        UsernamePasswordAuthenticationToken authenticationToken)
        throws AuthenticationException {

    // use dao here

これを説明してくれてありがとう

UPDATE:

調査を続けると、DAOSを使用しているDispatcherServletは子コンテキストであり、セキュリティコンテキストはどこか上位にあるようです。その結果、私のDispatcherServletのBeanは親コンテキストからは見えません。答えは、どういうわけか私のBean宣言を親アプリケーションのコンテキストに移動することだと思いますが、これを行う方法がわかりません。これが私のweb.xmlです

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

<listener>
    <listener-class>
        org.springframework.security.web.session.HttpSessionEventPublisher
    </listener-class>
</listener>

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

<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>

<servlet>
    <servlet-name>myapp</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>
    <init-param>
        <param-name>listings</param-name>
        <param-value>true</param-value>
    </init-param>
</servlet>

    ...

Daoのすべての作成物をspring-dao.xmlに移動し、spring-security.xmlで次のようにしています。

<import resource="spring-dao.xml" />

Daos stilはDispatcherServletコンテキストからは見えたままですが、私のSecurityContextからは見えません。

回答済み:

わかりました。ここにいくつかの役立つリンクがありました:

http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#context-create

http://forum.springsource.org/showthread.php?115774-Spring-Security-Custom-UserDetailsS​​ervice-to-use-User-Service-Dao

http://static.springsource.org/spring-security/site/faq.html#faq-method-security-in-web-context

したがって問題は、daoがApplicationContext(上位のスプリングコンテナー)に存在することを確認する必要があることでした。これが確実に行われるようにするために、web.xmlを次のように変更しました。

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>WEB-INF/spring-dao.xml WEB-INF/spring-security.xml
    </param-value>
</context-param>

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

<listener>
    <listener-class>
        org.springframework.security.web.session.HttpSessionEventPublisher
    </listener-class>
</listener>

<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>

<servlet>
    <servlet-name>webapp</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>
    <init-param>
        <param-name>listings</param-name>
        <param-value>true</param-value>
    </init-param>
</servlet>

これにより、起動する最初のコンテキストローダーが私のdao構成を読み取り(そして私のdao Beanを作成)、次に私のセキュリティ構成を確実に読み取るようになると思いました。 dao Beanがこの方法で作成されているので、以前の「import resource = "spring-dao.xml"」ステートメントは不要になったため、security.xmlから削除しました。

そのcontext-param構成の直後に、ContextLoaderListenerを作成しました。これはDispatcherServletよりも高レベルのSpringコンテナであるため、これを最初に配置すると、最初にこれらの構成ファイルを読み取ることができ、heがBeanを作成します。次に、すべての子コンテキストがそれらにアクセスできます。 DispatcherServletがcontextConfigLocationを読み取らない可能性があるため、これは機能しない可能性がありますが、読み取ったとしても、この時点でBeanはすでに宣言されているため、親コンテキストが所有していると考えました。

今、別のトリックのために...私のDAOを取得するために、私はそれをできません@ Autowiredでした。 XMLを介して手動で挿入する必要がありました。

    <bean id="userAuthenticationProvider" class="com.company.app.security.UserAuthenticationProvider">
    <property name="userDao" ref="userDao" />
</bean>

もちろん、私はdaoでゲッターメソッドとセッターメソッドを作成しました。 @Autowiredがここで機能しない理由はわかりません。仕様によるものと思います。おそらく、これはSecurityContext(他のコンテキストからプルされない)に固有であるか、または一般的に@Autowiredがonlyが現在のコンテキストからプルするか、またはBeanをXML、アノテーションではなくxmlでプロパティを設定する必要もありますか? (注釈が有効になっていて、最上位のアプリケーション名前空間で機能しています)。

とにかく、まだわかりませんが、重要な点は、ようやく機能していることです。

24
dev

Spring MVCを使用する場合は、必ず Spring MVCのApplicationContext階層を理解する が必要です。 サーブレットコンテナ内の基本コンポーネントとライフサイクル についても学ぶ必要があります。リスナーとサーブレットの動作についても混乱しているように思われるからです。

状況を簡単に説明するには:

  1. ルートコンテキストとDispatcherServletコンテキストの2つのApplicationContextを作成しています。ルートコンテキストは、contextConfigLocationで指定されたファイルに基づいてContextLoaderListenerによって作成されます。このコンテキストは、アプリのコアロジックを構成するBeanを含めることを目的としています。 DispatcherServletコンテキストは、そのサーブレットの起動時に作成され、「webapp-servlet.xml」という名前のファイルに基づいています。このコンテキストは、関連付けられているDispatcherServletインスタンスをサポートするすべてのBeanを含むことを目的としており、ビュー関連のBeanのみを含める必要があります。
  2. DispatcherServletコンテキストは、ルートコンテキストの子になります。これにより、ルートコンテキストのコアBeanをビューレイヤーBeanに挿入できます。可視性は一方向です。コアBeanではビューレイヤーBeanを使用できません。これは望ましいことです。これが、DAOを認証プロバイダーに挿入できなかった理由です。 DAOは子コンテキストにありました。
  3. 注釈ベースのサービスは、それらが宣言されているコンテキスト内でのみ適用されます。 @Autowiredが特定のBeanで機能しない場合は、そのBeanのコンテキストで <context:component-scan/> または <context:annotation-config/> を宣言していないことが原因です。存在します。
61
Ryan Stewart