2012-04-09 139 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); 
    } 

} 

我还创建了一个TournamentResource类,它是为比赛的REST前端。它的责任是做一些基本的验证(用户安全,...)和异常翻译。

@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而不是spring来instanciate TournamentController时,它的@Autowired属性似乎没有正确接线。我试图在其上添加@Component注释,但没有成功。

我应该通过弹簧TournamentResourceApplicationContextAware并创建TournamentController

这一定是一个相当普遍的问题。我看到很多后端是单例的例子,但是我想避免将Tournament传递给TournamentController上的每个方法调用(然后通过TournamentController中的所有私有方法)。

回答

1

由于您已经有加载时编织和<context:spring-configured />,因此您可以将TournamentController声明为@Configurable

它将启用用new创建的TournamentController实例的自动装配。

0

对,你用new创建的任何东西都不在Spring bean工厂的控制之下。拨打new意味着你是自己的。

我不确定为什么您的TournamentController需要私人参考Tournament。您可以说这是一个REST前端。如果我理解正确,REST基于HTTP,这是一种无状态协议。我不确定Tournament实例的来源。如果Spring实例化了TournamentController,那么您应该在注释或XML配置中引用有关锦标赛的引用。

我建议你让它成为一种Spring资源,它可以连接或重新考虑你的设计,从控制器中消除它。

+0

“TournamentController”基本上只是一个特定“锦标赛”的经理,因此任何时候都必须在比赛中完成某些事情(在任何给定时间将会进行多个锦标赛)。我希望它有一个私人参考“锦标赛”,所以我不必将“锦标赛”的参考传递给每个公共和私人方法。有点像中介模式。 – 2012-04-09 17:45:25

+0

所以它不是无状态的。您需要为用户提供REST方法,以便能够指定他们想要的锦标赛,这将是控制器中的注释方法。它不需要在里面有一个参考。你应该喜欢你不了解REST或调解员。 – duffymo 2012-04-09 17:47:08

+0

是的,这是我的休息方法的“@PathParam(”tournamentId“)”参数:-)。方法get的比赛ID,从持久中检索它,然后实例化TournamentController(传递比赛)引用,以便它可以在请求范围内对其进行操作。 – 2012-04-09 17:49:14