2011-12-01 15 views
7

Sto cercando di utilizzare Spring con Scala. So che Autowired funziona con la classe di Scala, ma sto usando un framework web che richiede un oggetto e voglio inserire un dao in esso. Mi chiedo come fare questo? Scusate, sono abbastanza nuovo di Scala, grazie in anticipo.Come utilizzare Spring Autowired (o cablato manualmente) nell'oggetto Scala?

@Service 
    object UserRest extends RestHelper { 
     @Autowired 
     @BeanProperty 
     val userRepository: UserRepository = null; 

     ..... 
    } 

    <beans> 
     ..... 
     <bean id="userRest" class="com.abc.rest.UserRest" > 
       <!--- this is my attempt to manually wire it ---> 
       <property name="userRepository" ref="userRepository"/> 
     </bean> 
    </beans> 
+0

perché hai bisogno di un oggetto qui? in ogni caso '@Service classe Hello {@Autowired var repos: Repository = _}' dovrebbe funzionare correttamente, supponendo che tu abbia configurato component-scan o utilizzando AnnotationConfigApplicationContext – OlegYch

risposta

12

In sostanza, si hanno due problemi:

  • proprietà deve essere mutevole, vale a dire var piuttosto che val

  • Tutti i metodi di Scala object sono static, mentre Primavera si aspetta metodi di istanza. In realtà Scala crea una classe con metodi di istanza denominati UserRest$ dietro la scena ed è necessario rendere disponibile la sua istanza singleton UserRest$.MODULE$ a Spring.
    Spring può applicare la configurazione a istanze singleton preesistenti, ma devono essere restituite da un metodo, mentre UserRest$.MODULE$ è un campo. Pertanto, è necessario creare un metodo per restituirlo.

Quindi, qualcosa di simile a questo dovrebbe funzionare:

object UserRest extends RestHelper { 
    @BeanProperty 
    var userRepository: UserRepository = null; 

    def getInstance() = this 
    ... 
} 

.

<bean id="userRest" 
    class="com.abc.rest.UserRest" 
    factory-method = "getInstance"> 
    <property name="userRepository" ref="userRepository"/> 
</bean> 

È possibile sostituire <property> con @Autowired, ma non può sostituire la dichiarazione di fagioli manuale con @Service causa di problemi con istanza Singleton sopra descritto.

Consulta anche:

+0

È davvero fantastico. Mi chiedo se c'è un modo diverso da XML per farlo con Spring 3.1. – sourcedelica

+0

@ericacm: In realtà, puoi creare un oggetto '@ Configuration' e restituire' UserRest $ .MODULE $ 'dal suo metodo annotato' @ Bean'. È già disponibile nella primavera 3.0. – axtavt

+0

Sì, buon punto. – sourcedelica

1

Quello che faccio è usare AutowiredAnnotationBeanPostProcessor per iniettare l'oggetto in fase di costruzione.

Ad esempio:

object UserRest extends RestHelper { 
    @Autowired 
    var userRepository: UserRepository = _ 

    AppConfig.inject(this) 
} 

@Configuration 
class AppConfig extends ApplicationListener[ContextRefreshedEvent] { 

    // Set the autowiredAnnotationBeanPostProcessor when the Spring context is initialized 
    def onApplicationEvent(event: ContextRefreshedEvent) { 
    autowiredAnnotationBeanPostProcessor = 
     event.applicationContext. 
     getBean(AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME). 
      asInstanceOf[AutowiredAnnotationBeanPostProcessor] 
    } 
} 

object AppConfig { 
    var autowiredAnnotationBeanPostProcessor: AutowiredAnnotationBeanPostProcessor = null 

    def inject(obj: AnyRef) { 
    autowiredAnnotationBeanPostProcessor.processInjection(obj); 
    } 
} 

Ora è possibile utilizzare AppConfig.inject() per iniettare qualsiasi oggetto la cui ciclo di vita non è controllata entro la primavera. Ad esempio, Entità JPA, ecc.

4

Tutto ciò che è effettivamente necessario è che si definisca il proprio oggetto come una classe, piuttosto che un oggetto. In questo modo la primavera lo renderà istantaneo.

@Service 
    object UserRest extends RestHelper { 
     @Autowired 
     @BeanProperty 
     val userRepository: UserRepository = null; 

     ..... 
    } 
<beans> 
     ..... 
     <bean id="userRest" class="com.abc.rest.UserRest" > 
       <!--- this is my attempt to manually wire it ---> 
       <property name="userRepository" ref="userRepository"/> 
     </bean> 
    </beans> 

Modifica della "val" a "var" è inutile (primavera utilizza la riflessione, che ignora immutabilità). Sono abbastanza sicuro che anche @BeanProperty non sia necessario (Spring assegnerà al campo sottostante, in modo riflessivo).soluzione

3

di axtavt non ha funzionato per me, ma la combinazione di diversi suggerimenti dalle altre risposte Penso che questa sia la soluzione più elegante:

object User { 
    @Autowired val repo: UserRepository = null 

    def instance() = this 
} 

@Configuration 
class CompanionsConfig { 
    @Bean def UserCompanion = User.instance 
} 

<context:component-scan base-package="your-package" /> 

Alcune note:

  • Utilizzando @Configuration assicura che gli oggetti del tuo accompagnatore sono attivati ​​con impazienza
  • L'uso di @Bean def evita di dover gestire nomi rumorosi Scala dà alla classe che implementa l'oggetto companion
  • val funziona bene, come detto da Dave Griffith
  • non v'è alcuna necessità di @BeanProperty di Scala, Primavera capisce proprietà Scala fuori dalla scatola (sto usando 3.2.2)
0

Oltre a https://stackoverflow.com/a/8344485/5479289, è anche possibile aggiungere Scala oggetto pacchetto alla primavera contesto, così come scala oggetto, utilizzando il metodo di fabbrica. L'oggetto pacchetto compilato è la solita classe java denominata pacchetto, quindi è possibile aggiungerla al contesto Spring. Dopo che avrete possibilità di tutti di primavera all'interno di questo oggetto, vale a dire @Autowired, @Value, cablaggio manuale ecc

pacchetto di prova:

package my.module 

package object A { 
    def getInstance = this 

    @Autowired 
    private val b: B = null 
} 

E la primavera contesto XML è:

<beans ...> 
    ... 
    <bean id="a" class="my.module.A.package" factory-method="getInstance"/> 
    ... 
</beans> 
Problemi correlati