Как использовать Spring Autowired (или вручную) в объекте Scala? - PullRequest
11 голосов
/ 01 декабря 2011

Я пытаюсь использовать Spring с Scala. Я знаю, что Autowired работает с классом Scala, но я использую веб-фреймворк, которому требуется объект, и я хочу внедрить в него дао. Интересно, как это сделать? Извините, я новичок в 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>

Ответы [ 6 ]

15 голосов
/ 01 декабря 2011

По сути, у вас есть две проблемы:

  • Свойство должно быть изменяемым, т.е. 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 из-за проблем с экземпляром singleton, описанным выше.

См. Также:

4 голосов
/ 02 декабря 2011

Все, что действительно необходимо, это то, что вы определяете свой объект как класс, а не как объект.Таким образом 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 будет рефлексивно назначать базовое поле).

3 голосов
/ 23 сентября 2013
Решение

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 работает просто отлично, так какупомянутый Дейвом Гриффитом
  • в Scala's @BeanProperty нет необходимости, Spring понимает свойства Scala из коробки (я использую 3.2.2)
1 голос
/ 16 мая 2018

Обычный Autowire из класса, помеченного @Component или @Bean, будет работать с вышеупомянутыми способами.

Но если вы хотите автоматически подключить интерфейс, расширяющий Jpa-репозиторий, убедитесь, что Dao не являетсяобъект, но класс.

ex:

DAO:

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

Это не будет работать (проверено).Я предполагаю, что, поскольку он определен как объект, его экземпляр создается во время выполнения с репо в качестве нулевого значения, следовательно, он не сможет автоматически связывать репо jpa.

Вместо этого объявите его как класс и пометьте @Component:

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

Это работает, так как мы даем Spring возможность управлять созданием объекта (@component), который автоматически связывает репозиторий jpa.

1 голос
/ 01 декабря 2011

Что я делаю, так это использую 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 и т. Д.

0 голосов
/ 13 ноября 2015

В дополнение к https://stackoverflow.com/a/8344485/5479289, также можно добавить объект пакета scala в контекст Spring, а также объект scala , используя фабричный метод. Объект скомпилированного пакета - это обычный java-класс с именем package , поэтому вы можете добавить его в контекст Spring. После этого у вас будут все возможности Spring внутри этого объекта, например, @ Autowired , @ Value , ручное подключение и т. Д.

Тестовый пакет:

package my.module

package object A {
  def getInstance = this

  @Autowired
  private val b: B = null
}

И весенний контекст xml:

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