How to use Spring Autowired (or manually wired) in Scala object?

后端 未结 8 1635
栀梦
栀梦 2020-12-28 19:12

I am trying to use Spring with Scala. I know Autowired works with Scala class, but I am using a web-framework that requires an object and I want to inject a dao into it. I w

相关标签:
8条回答
  • 2020-12-28 19:51

    I faced same issue.
    I have many services and want to call these @Autowired service from scala objects.
    I tried all the above, None of them worked as my expectation.
    I have an object named JobConfig.scala and I want to autowire TableResolver class and TableResolver class itself autowire many other classes.

    My application is in spring boot and scala.

    1. Add src/main/resources/applicationContext.xml file.
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">
    
        <bean id="jobId" class="package.JobConfig"
              factory-method="getInstance">
        </bean>
    
    </beans>
    
    1. Add XmlBeansConfig.scala
    import org.springframework.context.annotation.{Configuration, ImportResource}
    
    @Configuration
    @ImportResource(value = Array("classpath*:applicationContext.xml"))
    class XmlBeansConfig {
    }
    
    1. Inside JobConfig.scala
    object JobConfig{
      def getInstance = this
    
      @Autowired
      var tableResolver: TableResolver = _
    }
    
    0 讨论(0)
  • 2020-12-28 20:05

    In addition to https://stackoverflow.com/a/8344485/5479289, it's also possible to add scala package object to Spring context, as well as scala object, using factory method. Compiled package object is usual java class named package, so you can add it to Spring context. After that you will have all Spring's possibilities inside this object, i.e @Autowired, @Value, manual wiring etc.

    Test package:

    package my.module
    
    package object A {
      def getInstance = this
    
      @Autowired
      private val b: B = null
    }
    

    And spring context xml is:

    <beans ...>
      ...
      <bean id="a" class="my.module.A.package" factory-method="getInstance"/>
      ...
    </beans>
    
    0 讨论(0)
  • 2020-12-28 20:06

    axtavt's solution did not work for me, but combining different suggestions from the other answers I think this is the most elegant solution:

    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" />
    

    A few notes:

    • Using @Configuration ensures that your companion objects are eagerly autowired
    • Using @Bean def avoids having to deal with noisy names Scala gives to the class that implements the companion object
    • val works just fine, as mentioned by Dave Griffith
    • there is no need for Scala's @BeanProperty, Spring understands Scala properties out of the box (I'm using 3.2.2)
    0 讨论(0)
  • 2020-12-28 20:07

    Normal Autowire from a class that is marked with @Component or @Bean would work with above mentioned ways.

    But if you want to auto wire an interface extending Jpa repository then make sure the Dao is not an object but class.

    ex:

    DAO:

    object dao{
     @Autowired val repo: jpaRepo = null
    }
    

    This won't work (tested). My guess is that since it's defined as an object, gets instantiated at run time with repo as null value, hence won't be able to autowire jpa repo.

    Instead declare it as class and mark with @Component:

    @Component
    class dao{
    @Autowired val repo: jpaRepo = null
    }
    

    It works since we are letting spring to manage the object creation(@component) that autowires jpa repo properly.

    0 讨论(0)
  • 2020-12-28 20:10

    What I do is use AutowiredAnnotationBeanPostProcessor to inject the object at construction time.

    For example:

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

    Now you can use AppConfig.inject() to inject any object whose lifecycle is not controlled by Spring. For example, JPA Entities, etc.

    0 讨论(0)
  • 2020-12-28 20:11

    None of the previous answears worked for me, but after some struggle I could solve it like this:

    @Service
    class BeanUtil extends ApplicationContextAware {
    
        def setApplicationContext(applicationContext: ApplicationContext): Unit = BeanUtil.context = applicationContext
    
    }
    
    object BeanUtil {
        private var context: ApplicationContext = null
    
        def getBean[T](beanClass: Class[T]): T = context.getBean(beanClass)
    }
    

    an then the object:

    object MyObject {
        val myRepository: MyRepository = BeanUtil.getBean(classOf[MyRepository])
    }
    
    0 讨论(0)
提交回复
热议问题