2012-10-30 26 views
11

jose 1.13とtomcat 6で動作するspring 3.1.1を使用して休憩サービスを作成しました。 Tomcatでは認証を行う領域を使用しています。 私のアプリケーションでは現在のユーザーが必要ですが、すべてのリソースのjerseyからSecurityContextにアクセスしたくありません。私は、現在のユーザを含む残りのリソースにリクエストスコープのApplicationConfigオブジェクトを注入したいと思います。後でこのクラスを拡張して、より多くのリクエストレベルのコンフィグレーションパラメータを含めることができます。これは私にとって素晴らしい抽象的なようです。ContainerRequestFilterでSpringリクエストスコープBeanを設定する

@Component 
@Scope(value = "request") 
public class ApplicationConfig 
{ 
    private String userCode; 

    public String getUserCode() 
    { 
     return this.userCode; 
    } 

    public void setUserCode(String userCode) 
    { 
     this.userCode = userCode; 
    } 
} 

構成にアクセスできるようにApplicationConfigManagerを作成しました。

@Component 
public class ApplicationConfigManager 
{ 
    @Autowired 
    public ApplicationConfig applicationConfig; 

    public ApplicationConfig getApplicationConfig() 
    { 
     return this.applicationConfig; 
    } 
} 

アプリケーションの設定マネージャはシングルトン(デフォルト)として定義されているが、ApplicationConfigはしたがって@Scopeアノテーション、要求範囲であるべきです。

私は(ジャージー)ContainerRequestFilterを使用して、アプリケーション設定オブジェクトでユーザーを設定しています。

@Component 
@Provider 
public class ApplicationConfigFilter implements ResourceFilter, ContainerRequestFilter 
{ 
    @Autowired 
    private ApplicationConfigManager applicationConfigManager; 

    @Override 
    public ContainerRequest filter(ContainerRequest request) 
    { 
     this.applicationConfigManager.getApplicationConfig().setUserCode(
      request.getSecurityContext().getUserPrincipal().getName() 
     ); 
     return request; 
    } 

    @Override 
    public ContainerRequestFilter getRequestFilter() 
    { 
     return this; 
    } 

    @Override 
    public ContainerResponseFilter getResponseFilter() 
    { 
     return null; 
    } 
} 

私はまた、これらのリスナーは、春のブートストラップに追加私はweb.xmlの

<servlet> 
    <servlet-name>Jersey REST Service</servlet-name> 
    <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class> 
    <init-param> 
     <param-name>com.sun.jersey.config.property.packages</param-name> 
     <param-value>com.mypackage</param-value> 
    </init-param> 
    <init-param> 
     <param-name>com.sun.jersey.spi.container.ResourceFilters</param-name> 
     <param-value>com.mypackage.ResourceFilterFactory</param-value> 
    </init-param> 
    <load-on-startup>1</load-on-startup> 
</servlet> 

にこれを設定することで、この工場を起動し、私はResourceFilterFactory

@Component 
@Provider 
public class ResourceFilterFactory extends RolesAllowedResourceFilterFactory 
{ 
    @Autowired 
    private ApplicationConfigFilter applicationConfigFilter; 

    @Override 
    public List<ResourceFilter> create(AbstractMethod am) 
    { 
     // get filters from RolesAllowedResourceFilterFactory Factory! 
     List<ResourceFilter> rolesFilters = super.create(am); 
     if (null == rolesFilters) { 
      rolesFilters = new ArrayList<ResourceFilter>(); 
     } 

     // Convert into mutable List, so as to add more filters that we need 
     // (RolesAllowedResourceFilterFactory generates immutable list of filters) 
     List<ResourceFilter> filters = new ArrayList<ResourceFilter>(rolesFilters); 

     filters.add(this.applicationConfigFilter); 

     return filters; 
    } 
} 

を作成し、このフィルタを登録するにはコンテキストを有効にして要求スコープを有効にする

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

これは私が

<context:annotation-config/> 
<context:component-scan base-package="com.mypackage" /> 

<bean id="applicationConfig" class="com.mypackage.ApplicationConfig" scope="request"/> 

そして今、私の(私は春が自動的にそれを見つけるでしょう、これは必要すらないと思います)スキャン機能の作業を取得するとaplicationのconfigオブジェクトを定義するために自分のアプリケーションのコンテキストに入れものです問題。私がアプリケーションを起動すると、Springはブートストラップされ、ApplicationConfigオブジェクトをApplicationConfigFilterに注入されたApplicationConfigManagerに注入します。

この時点では、例外がスローされます:

. 
. 
Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually o 
perating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request. 
     at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131) ~[spring-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
     at org.springframework.web.context.request.AbstractRequestAttributesScope.get(AbstractRequestAttributesScope.java:40) ~[spring-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
     at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:328) ~[spring-beans-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
     ... 57 common frames omitted 

この例外はかなり明確であり、私はそれは要求が全く要求がまだ送信されなかったためにApplicationConfigを注入することができないスコープの意味だと思います。

私はApplicationConfigオブジェクトをインスタンス化する必要があります。要求が送信されたときだけで、アプリケーションの起動時ではありません。私は解決策を探して、リクエストスコープのBeanをシングルトンBeanに注入することはあまり論理的ではないことを発見しました。とにかく私はいつも同じオブジェクトを得るでしょう。解決策は、私は私のすべての要求のための新しいApplicationConfigオブジェクトを与える必要があります。この

@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS) 

これにApplicationConfigクラスに@Scopeアノテーションを変更して、プロキシを使用することです。

アプリケーションは今すぐ起動します(ApplicationConfigをインスタンス化しているようには見えません)が、私のレストサービスにリクエストを送信すると、デバッグを使用して、同じApplicationConfigオブジェクトの代わりに、リクエスト。

どうしたのですか?

答えて

7

これを使って遊んだ後、@ScopeアノテーションのproxyMode設定がとにかくやっていることがわかりました。それが解決策です。プロキシは毎回新しいインスタンスを作成する際に注意を払い、リクエストスコープであることを確認します。

関連する問題