24

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

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

アップデート:

調査を続けると、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 は 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 はこの方法で作成されているため、security.xml 内の以前の "import resource="spring-dao.xml"" ステートメントは不要になるため削除しました。

その context-param 構成の直後に、ContextLoaderListener を作成しました。これは DispatcherServlet よりも高レベルの Spring コンテナーであるため、これを最初に配置すると、最初に構成ファイルを読み取り、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 は通常、現在のコンテキストからのプルするか、または XML を介して Bean を作成したため、xml を介してプロパティも設定する必要があります。注釈経由ではありませんか?(注釈は有効になっており、最上位のアプリケーション名前空間で機能しています)。

とにかく..まだわからないことがたくさんありますが、重要な点は、ようやく機能するようになったことです。

4

1 に答える 1

61

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 で機能しない場合は、宣言していない<context:component-scan/><context:annotation-config/>、その Bean が存在するコンテキストにいないためです。
于 2011-10-13T00:26:26.627 に答える