弹簧非单件控制器

时间:2012-04-09 17:24:38

标签: spring

我正在构建一个基于Spring的应用程序,用于处理移动游戏应用程序的服务器端游戏管理。堆栈是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班级是单身设计,运作良好。

我的问题是,当它使用TournamentController而不是弹簧来new实例化时,它的@Autowired属性似乎没有正确连接。我尝试在其上添加@Component注释但没有成功。

我应该TournamentResource ApplicationContextAware并通过春天创建TournamentController吗?

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

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:0)

是的,使用new创建的任何内容都不在Spring bean工厂的控制之下。致电new意味着您自己。

我不确定为什么您的TournamentController需要私人引用Tournament。你明确指出这是一个REST前端。如果我理解正确,REST基于HTTP,这是一种无状态协议。

我不确定您认为Tournament实例的来源。如果Spring实例化TournamentController,那么您应该在注释或XML配置中连接对相关锦标赛的引用。

我建议你把它作为一个Spring资源,连接或重新考虑你的设计,以便从Controller中消除它。