Spring Framework и java-подобные сборщики объектов в Scala

#spring #scala #cake-pattern

#spring #scala #шаблон для торта

Вопрос:

В Spring framework и Java world есть интересный шаблон сборщика объектов, который я использую. Например, рассмотрим ниже —

 public interface Calculator {
    SomeOutput calculate(SomeInput input);
}

@Component
public class CalImpl1 implements Calculator {
 public SomeOutput calculate(SomeInput input){
  //some implementation
 }
}

@Component
public class CalImpl2 implements Calculator {
 public SomeOutput calculate(SomeInput input){
  //some implementation
 }
}
  

Теперь это можно легко внедрить в другой класс, используя Spring DI

 @Component
public class Main {

 //This line collects all to implementors of this and set it here.
 @Autowired
 public List<Calculator> calculators;

 //other methods
}
  

Теперь проблема в том, что я не уверен, как то же самое можно достичь в scala. Я провел некоторый поиск и нашел шаблон cake (http://loicdescotte.github.io/posts/scala-di /) используется в scala, но, похоже, это не дает того же результата, что и сборщики объектов, как описано выше. Я также хочу следовать принципу open close, который, я думаю, нарушается в шаблоне cake, но, используя сборщики объектов, я могу легко достичь этого.

есть ли способ добиться таких же сборщиков объектов, как реализация в scala?

Комментарии:

1. Это скорее особенность контейнера DI, чем общий шаблон. т. Е. Автоматическое подключение, когда встречается список, рассмотрит возможность введения нескольких совпадающих компонентов. Если вы не предоставите нам больше информации о том, какой контейнер DI вы используете в Scala, практически невозможно дать соответствующий и значимый ответ. Учитывая, что вы можете использовать Spring с Scala, я думаю, что то, чего вы хотите достичь, все равно будет работать, если вы используете Spring в своем проекте Scala

2. Я могу использовать абсолютно любой фреймворк, который позволяет мне достичь того же в scala.

3. Итак, учитывая, что Spring работает со Scala, я считаю, что такое поведение при внедрении все равно должно быть доступно, так в чем причина, по которой оно не используется или как оно не работает?

4. Тот же пример, что и выше, не работает для scala (после настройки небольших синтаксисов scala и использования trait вместо интерфейса и т. Д.).

5. Не знаком с Scala, просто хочу знать, работает ли это, если есть только 1 Calculator компонент, и вы подключаете a Calculator вместо List<Calculator> ? Потому что я считаю, что это поведение Spring, которое не должно зависеть от языка (при условии, что сгенерированный код эквивалентен Java с 1. компоненты реализуют Calculator интерфейс 2. @Autowired поле имеет тип List с правильным параметром типа.

Ответ №1:

В lighbend activator есть шаблоны, иллюстрирующие использование spring DI в приложениях Play, Akka и Scala. Пожалуйста, посмотрите это: https://www.lightbend.com/activator/templates#filter:spring

Я не использовал Spring в качестве DI, я обычно использую Guice (явно используется, потому что он используется по умолчанию в play framework 2) и подразумевает параметры как для компиляции DI.

Пример:

 class B

class X(x: Int)(implicit c: B)

//DI - mostly define in main method/application

implicit val c: B = new B
val x = new X(2)
  

Ответ №2:

Явное использование java.util.List сработало для меня. Это не самое красивое решение, но оно показывает, что оно в основном работает. Не пробовал этого, но, реализуя соответствующий PropertyEditor , вы могли бы придерживаться типов Scala.

 trait Calculator {
   def calculate(input: SomeInput) : SomeOutput
}

@Component
class CalImpl1 extends Calculator {
    override def calculate(input: SomeInput): SomeOutput = ...
}

@Component
class CalImpl2 extends Calculator {
  override def calculate(input: SomeInput): SomeOutput = ...
}

@Component
class Main @Autowired()(calculators: java.util.List[Calculator]) {
    // or inject field if constructor injection is not desired
    // @Autowired
    // var calculators: java.util.List[Calculator] = _
}

object Main {
    def main(args: Array[String]) = {
        val ctx = new AnnotationConfigApplicationContext("your package name here")
        val main = ctx.getBean(classOf[Main])
        // calculators should now be wired in the returned instance
  }
}
  

Комментарии:

1. вы пробовали этот пример в работе? Я не уверен, работает ли это.

2. Да, работает для меня. Просто обновил код, добавив небольшой метод main. Запуская его как отдельное приложение, я получаю Main экземпляр, который calculators правильно подключен. Также заменено @Inject на @Autowired . Не имеет никакого значения, но, возможно, был какой-то источник путаницы?