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

发布于 2024-12-18 22:08:24 字数 613 浏览 4 评论 0原文

我正在尝试将 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>

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 wonder how to do this? Sorry, I am quite new to Scala, thanks in advance.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

萧瑟寒风 2024-12-25 22:08:24

基本上,您有两个问题:

  • 属性应该是可变的,即 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>

您可以将 替换为 @Autowired,但由于上述单例实例的问题,无法将手动 bean 声明替换为 @Service

另请参阅:

Basically, you have two problems:

  • Property should be mutable, i.e. var rather than val

  • All methods of Scala object are static, whereas Spring expects instance methods. Actually Scala creates a class with instance methods named UserRest$ behind the scene, and you need to make its singleton instance UserRest$.MODULE$ available to Spring.
    Spring can apply configuration to preexisting singleton instances, but they should be returned by a method, whereas UserRest$.MODULE$ is a field. Thus, you need to create a method to return it.

So, something like this should work:

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>

You can replace <property> with @Autowired, but cannot replace manual bean declaration with @Service due to problems with singleton instance described above.

See also:

猫性小仙女 2024-12-25 22:08:24

实际上所需要的只是将对象定义为类,而不是对象。这样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 将反射地分配给底层字段)。

All that's actually necessary is that you define your object as a class, rather than an object. That way Spring will instantiate it.

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

Changing the "val" to "var" is unnecessary (Spring uses reflection, which ignores immutability). I'm pretty sure that that @BeanProperty is also unnecessary (Spring will assign to the underlying field, reflectively).

客…行舟 2024-12-25 22:08:24

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)

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)
假面具 2024-12-25 22:08:24

我所做的是使用 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 实体等。

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.

深空失忆 2024-12-25 22:08:24

使用 @Component 或 @Bean 标记的类中的普通 Autowire 将按照上述方式工作。

但是,如果您想自动连接扩展 Jpa 存储库的接口,请确保 Dao 不是对象而是类。

例如:

DAO:

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

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

相反,将其声明为类并使用 @Component 进行标记:

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

它可以工作,因为我们让 spring 来管理正确自动装配 jpa 存储库的对象创建(@component)。

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.

永言不败 2024-12-25 22:08:24

之前的答案都不适合我,但经过一番努力,我可以像这样解决它:

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

然后是对象:

object MyObject {
    val myRepository: MyRepository = BeanUtil.getBean(classOf[MyRepository])
}

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])
}
魂ガ小子 2024-12-25 22:08:24

除了 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 上下文 xml 是:

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

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>
断桥再见 2024-12-25 22:08:24

我遇到了同样的问题。
我有很多服务,想从 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 = _
}

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 = _
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文