如何在Scala对象中使用Spring Autowired(或手动连线)?

时间:2011-12-01 15:54:27

标签: spring scala lift autowired

我正在尝试将Spring与Scala一起使用。我知道Autowired可以使用Scala类,但我使用的是需要一个对象的Web框架,我想在其中注入一个dao。我想知道该怎么做?对不起,我对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>

8 个答案:

答案 0 :(得分:15)

基本上,你有两个问题:

  • 属性应该是可变的,即var而不是val

  • Scala object的所有方法都是static,而Spring需要实例方法。实际上,Scala在场景后面创建了一个名为UserRest$的实例方法的类,你需要让它的单例实例UserRest$.MODULE$可用于Spring。 Spring可以将配置应用于预先存在的单例实例,但它们应该由方法返回,而UserRest$.MODULE$是一个字段。因此,您需要创建一个返回它的方法。

所以,这样的事情应该有效:

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>

您可以将<property>替换为@Autowired,但由于上述单例实例存在问题,无法用@Service替换手动bean声明。

另见:

答案 1 :(得分:4)

所有实际需要的是将对象定义为类,而不是对象。那样Spring会实例化它。

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

将“val”更改为“var”是不必要的(Spring使用反射,忽略了不变性)。我很确定@BeanProperty也是不必要的(Spring会反过来分配给底层字段)。

答案 2 :(得分:3)

axtavt的解决方案对我不起作用,但结合其他答案的不同建议我认为这是最优雅的解决方案:

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

一些注意事项:

  • 使用@Configuration确保您的伴随对象热切地自动装配
  • 使用@Bean def避免必须处理Scala给实现伴随对象的类的嘈杂名称
  • val工作正常,如Dave Griffith所述
  • 不需要Scala的@BeanProperty,Spring开箱即用Scala属性(我使用的是3.2.2)

答案 3 :(得分:1)

我所做的是使用AutowiredAnnotationBeanPostProcessor在施工时注入对象。

例如:

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

现在,您可以使用AppConfig.inject()来注入生命周期不受Spring控制的任何对象。例如,JPA实体等

答案 4 :(得分:1)

使用@Component或@Bean标记的类的正常自动装配可以使用上述方法。

但是如果你想自动连接一个扩展Jpa存储库的接口,那么确保Dao不是一个对象而是类。

例如:

DAO:

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

这不起作用(测试过)。我的猜测是,因为它被定义为一个对象,在运行时使用repo作为空值进行实例化,因此无法自动装配jpa repo。

而是将其声明为类并使用@Component标记:

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

它起作用,因为我们让spring来管理自动装配jpa repo的对象创建(@component)。

答案 5 :(得分:1)

以前的answears都没有为我工作,但是经过一番挣扎之后,我可以这样解决它:

public class XsDevice implements XsensDotDeviceCb, Serializable {
    private MutableLiveData<ArrayList<Float>> accelerationData = new MutableLiveData<>();
    public LiveData<ArrayList<Float>> freeAccDataLiveData = accelerationData;

    ...

    @Override
    public void onXsensDotDataChanged(String s, XsensDotData xsensDotData) {
        ArrayList<Float> result = new ArrayList();

        for (Float freeAcc: xsensDotData.getFreeAcc()) {
            result.add(freeAcc);
        }
        accelerationData.postValue(result);
    }
}

然后是对象:

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

答案 6 :(得分:0)

除了https://stackoverflow.com/a/8344485/5479289之外,还可以使用工厂将scala 包对象添加到Spring上下文,以及scala 对象方法。编译的包对象通常是名为 package 的java类,因此可以将其添加到Spring上下文中。在此之后,您将拥有Spring的所有可能性,即 @Autowired @Value ,手动布线等。

测试包:

package my.module

package object A {
  def getInstance = this

  @Autowired
  private val b: B = null
}

Spring context xml是:

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

答案 7 :(得分:0)

我遇到了同样的问题。
我有很多服务,想从scala对象中调用这些@Autowired服务。
我尝试了以上所有方法,但都没有达到我的期望。
我有一个名为JobConfig.scala的对象,我想自动装配TableResolver类,而TableResolver类本身可以自动装配许多其他类。

我的应用程序在spring boot和scala中。

  1. 添加src/main/resources/applicationContext.xml文件。
<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. 添加XmlBeansConfig.scala
import org.springframework.context.annotation.{Configuration, ImportResource}

@Configuration
@ImportResource(value = Array("classpath*:applicationContext.xml"))
class XmlBeansConfig {
}
  1. JobConfig.scala
object JobConfig{
  def getInstance = this

  @Autowired
  var tableResolver: TableResolver = _
}