2011-12-01 16 views
7

Estoy tratando de usar Spring with Scala. Sé que Autowired funciona con la clase Scala, pero estoy usando un framework web que requiere un objeto y quiero inyectar un dao en él. Me pregunto cómo hacer esto? Lo siento, soy bastante nuevo en Scala, gracias de antemano.Cómo usar Spring Autowired (o cableado manual) en el objeto 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

¿por qué necesita un objeto aquí? de todos modos '@ Clase de servicio Hola {@ Var variado autoajustado: Repository = _}' debería funcionar bien, suponiendo que haya configurado el componente-scan o que use AnnotationConfigApplicationContext – OlegYch

Respuesta

12

Básicamente, tiene dos problemas:

  • propiedad debe ser mutable, es decir var en lugar de val

  • Todos los métodos de Scala object son static, mientras que la primavera espera que los métodos de instancia. En realidad, Scala crea una clase con métodos de instancia llamados UserRest$ detrás de la escena, y usted necesita hacer que su instancia singleton UserRest$.MODULE$ esté disponible para Spring.
    Spring puede aplicar la configuración a instancias singleton preexistentes, pero deben devolverse mediante un método, mientras que UserRest$.MODULE$ es un campo. Por lo tanto, debe crear un método para devolverlo.

Por lo tanto, algo como esto debería funcionar:

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> 

Se puede reemplazar con <property>@Autowired, pero no puede sustituir a la declaración de frijol manual con @Service debido a problemas con instancia singleton descrito anteriormente.

Consulte también:

+0

Eso es genial. Me pregunto si hay una forma no xml de hacerlo con Spring 3.1. – sourcedelica

+0

@ericacm: en realidad, puede crear un objeto '@ Configuration' y devolver' UserRest $ .MODULE $ 'desde su método' @ Bean'-annotated. Ya está disponible en Spring 3.0. – axtavt

+0

Sí, buen punto. – sourcedelica

1

Lo que hago es usar AutowiredAnnotationBeanPostProcessor para inyectar el objeto en tiempo de construcción.

Por ejemplo:

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); 
    } 
} 

Ahora puede utilizar AppConfig.inject() para inyectar cualquier objeto cuyo ciclo de vida no está controlada por resorte. Por ejemplo, entidades JPA, etc.

4

Todo lo que realmente es necesario es que defina su objeto como una clase, en lugar de como un objeto. De esa manera, Spring lo instanciará.

@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> 

Cambio de la "val" a "var" es innecesaria (primavera utiliza la reflexión, que ignora la inmutabilidad). Estoy bastante seguro de que @BeanProperty también es innecesario (Spring lo asignará al campo subyacente, de forma reflexiva).solución

3

de axtavt no funcionó para mí, pero la combinación de diferentes sugerencias de las otras respuestas creo que esta es la solución más 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" /> 

Unas pocas notas:

  • Usando @Configuration asegura que los objetos de su compañero están ansiosamente autoconectados
  • Usando @Bean def evita tener que lidiar con nombres ruidosos Scala da a la clase que implementa el objeto complementario
  • val funciona bien, como se ha mencionado por Dave Griffith
  • no hay necesidad de @BeanProperty de Scala, Primavera entiende propiedades Scala fuera de la caja (estoy usando 3.2.2)
0

Además de https://stackoverflow.com/a/8344485/5479289, también es posible agregar el objeto de paquete scala al contexto de Spring, así como también el objeto de scala, utilizando el método de fábrica. El objeto de paquete compilado es la clase java habitual llamada paquete, por lo que puede agregarlo al contexto de Spring. Después de que va a tener posibilidades de toda la primavera dentro de este objeto, es decir @Autowired, @Valor, etc. cableado manual de

paquete de prueba:

package my.module 

package object A { 
    def getInstance = this 

    @Autowired 
    private val b: B = null 
} 

Y la primavera contexto XML es:

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