私は、モバイルゲームアプリケーションのサーバー側のゲーム管理を処理するスプリングベースのアプリケーションを構築しています。スタックは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
注釈を成功させることなく追加しようとしました。
TournamentResource
ApplicationContextAware
を作成し、春からTournamentController
を作成する必要がありますか?
これはかなり一般的な問題であるに違いありません。私は、バックエンドがシングルトンである例をたくさん見ていますが、TournamentController
(すべてのプライベートメソッドすべてをTournamentController
)のすべてのメソッド呼び出しにTournament
を渡すことは避けたいと思います。
"TournamentController"は基本的に特定の "トーナメント"のマネージャーなので、トーナメントで何かが行われなければいつでもインスタンス化されます(複数のトーナメントがいつでも実行されます)。「トーナメント」への個人的な参照が必要なので、「トーナメント」への参照をすべての公開方法と非公開方法に渡す必要はありません。メディエーターパターンのようなもの。 –
したがって、ステートレスではありません。ユーザーがどのトーナメントを希望するかを指定できるようにするには、RESTメソッドを用意する必要があります。これはコントローラーの注釈付きメソッドになります。それの内部に参照を持つ必要はありません。あなたはRESTやメディエーターを理解していないようにすべきです。 – duffymo
これは、私のrestメソッドの "@PathParam(" tournamentId ")"パラメータです:-)。このメソッドは、トーナメントIDを取得し、永続性から取得して、トーナメントを渡す(トーナメントを渡す)参照を要求のスコープ内で実行できるようにインスタンス化します。 –