2012-04-09 5 views
0

私は、モバイルゲームアプリケーションのサーバー側のゲーム管理を処理するスプリングベースのアプリケーションを構築しています。スタックはSpring/Hibernate/Jerseyです。私は、クライアント(モバイル)がゲームの状態を更新/取得するためにREST APIを呼びたいと思っています。スプリング非シングルトンコントローラ

私はTournamentControllerクラスを作成しました。この責任は、ビジネスロジックを使用してトーナメントの状態を更新することです。このクラスはトーナメントの操作が必要とされ、投げ捨てられるたびにインスタンス化されるように設計されています。

public class TournamentController { 

    @Autowired 
    private TournamentDAO tournamentDAO; 

    private final Tournament tournament; 

    public TournamentController(Tournament tournament) { 
     this.tournament = tournament; 
    } 

    public void startTournament() { 
     if (tournament.getState() != TournamentState.SETUP) { 
      throw new TournamentAlreadyStartedException(); 
     } 

     tournament.setState(TournamentState.IN_PROGRESS); 

     //... some other logic and calls to other DAOs 

     tournamentDAO.save(tournament); 
    } 

} 

私はまたトーナメントのためのRESTのフロントエンドであるTournamentResourceクラスを作成しました。それは、いくつかの基本的な検証(ユーザーセキュリティ、...)と例外翻訳を行う責任があります。

@Path("/tournament") 
@Component 
@Scope("prototype") 
public class TournamentResource { 

    private static final Log log = LogFactory.getLog(TournamentResource.class); 

    @Autowired 
    private TournamentDAO tournamentDAO; 

    @GET 
    @Path("{tournamentId}/start") 
    @Produces(MediaType.APPLICATION_JSON) 
    @Transactional 
    public TournamentDTO startTournament(@PathParam("tournamentId") long tournamentId) { 
     Tournament tournament = tournamentDAO.getTournament(tournamentId, LockMode.PESSIMISTIC_WRITE); 
     if (tournament == null) { 
      throw new WebApplicationException(Status.NOT_FOUND); 
     } 

     try { 
      TournamentController controller = new TournamentController(tournament); 
      controller.startTournament(); 

     } catch (TournamentAlreadyStartedException e) { 
      log.warn("Could not start tournament " + tournamentId + " since it is already started."); 
      throw new RestException(Status.BAD_REQUEST, "Tournament already started"); 
     } 

     return DTOConverterUtil.getTournament(tournament); 
    } 

} 

私はAspectJでロードタイム織りを使用しています。ここに私の状況は次のとおりです。

<context:annotation-config /> 

    <!-- Make spring aware ANY pojo with the @Configurable annotation --> 
    <context:spring-configured /> 

    <!-- Scan all classes in com.mdarveau for annotations --> 
    <context:component-scan base-package="so.question" /> 

    <!-- Load Time Weaver --> 
    <context:load-time-weaver weaver-class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" aspectj-weaving="on" /> 

    <!-- DB config --> 
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> 
     ... 
    </bean> 

    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> 
     <property name="dataSource" ref="dataSource" /> 
     <property name="packagesToScan" value="com.mdarveau.fnp.model" /> 
     <property name="hibernateProperties"> 
     <value> 
      hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect 
     </value> 
     </property> 
    </bean> 

    <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
     <property name="sessionFactory" ref="sessionFactory" /> 
    </bean> 

    <!-- enable @Transactional --> 
    <tx:annotation-driven transaction-manager="txManager" mode="aspectj" /> 

TournamentResourceクラスは、設計によって、シングルトンで、うまく機能しています。

私の問題は、スプリングの代わりにnewを使用してTournamentControllerをインスタンス化すると、@Autowiredの属性が正しく配線されていないように見えるということです。私はそれに@Component注釈を成功させることなく追加しようとしました。

TournamentResourceApplicationContextAwareを作成し、春からTournamentControllerを作成する必要がありますか?

これはかなり一般的な問題であるに違いありません。私は、バックエンドがシングルトンである例をたくさん見ていますが、TournamentController(すべてのプライベートメソッドすべてをTournamentController)のすべてのメソッド呼び出しにTournamentを渡すことは避けたいと思います。

答えて

1

すでにローディング時間があり、<context:spring-configured />があるので、TournamentController@Configurableと宣言できます。

newで作成されたTournamentControllerのインスタンスの自動配線を有効にします。

0

右は、newで作成したものは、Spring Beanファクトリの制御下にありません。 newを呼び出すことはあなた自身で行うことを意味します。

TournamentControllerTournamentのプライベートリファレンスが必要な理由がわかりません。あなたはこれがRESTのフロントエンドであると言います。正しく理解すれば、RESTはステートレスなプロトコルであるHTTPに基づいています。

Tournamentインスタンスがどこから来るかはわかりません。 SpringがTournamentControllerをインスタンス化する場合は、問題のトーナメントへの参照をアノテーションまたはXML構成で配線する必要があります。

私は、あなたがコントローラに接続しないようにデザインに配線したり再考したりするSpringリソースにすることをお勧めします。

+0

"TournamentController"は基本的に特定の "トーナメント"のマネージャーなので、トーナメントで何かが行われなければいつでもインスタンス化されます(複数のトーナメントがいつでも実行されます)。「トーナメント」への個人的な参照が必要なので、「トーナメント」への参照をすべての公開方法と非公開方法に渡す必要はありません。メディエーターパターンのようなもの。 –

+0

したがって、ステートレスではありません。ユーザーがどのトーナメントを希望するかを指定できるようにするには、RESTメソッドを用意する必要があります。これはコントローラーの注釈付きメソッドになります。それの内部に参照を持つ必要はありません。あなたはRESTやメディエーターを理解していないようにすべきです。 – duffymo

+0

これは、私のrestメソッドの "@PathParam(" tournamentId ")"パラメータです:-)。このメソッドは、トーナメントIDを取得し、永続性から取得して、トーナメントを渡す(トーナメントを渡す)参照を要求のスコープ内で実行できるようにインスタンス化します。 –

関連する問題