Я думаю, что для разработчиков выбор правильного инструмента сборки — очень важный выбор. В течение многих лет я придерживался Apache Maven и, честно говоря, он выполняет свою работу достаточно хорошо, даже сейчас это хороший инструмент для использования. Но я всегда чувствую, что это можно сделать намного лучше … а потом появился Градл …
Несмотря на то, что я потратил много часов на то, чтобы привыкнуть к Gradle , я наконец сдался и вернулся к Apache Maven . Причина — я не чувствовал себя комфортно с этим, в основном из-за Groovy DSL. В любом случае, я думаю, что Gradle — это отличный, мощный и расширяемый инструмент для сборки, который способен выполнять любые задачи, которые нужны вашему процессу сборки.
Но все больше и больше занимаясь Scala , я быстро обнаружил, что кто-то другой . Хотя sbt является аббревиатурой от « простого инструмента сборки », мое первое впечатление было совершенно противоположным: я нашел его сложным и трудным для понимания. По некоторым причинам, мне все же понравилось, и, проводя больше времени за чтением документации (которая становится все лучше и лучше), во многих экспериментах, я бы, наконец, сказал, что выбор сделан. В этой статье я хотел бы показать пару замечательных вещей, которые sbt может сделать, чтобы облегчить жизнь Java-разработчику (некоторые знания Scala были бы очень полезны, но это не обязательно).
Прежде чем перейти к реальному примеру, пара фактов о sbt . Он использует Scala в качестве языка для сценария сборки и требует запуска, который можно скачать отсюда (версия, которую мы будем использовать, — 0.13.1 ). Есть несколько способов описать сборку в sbt , один из которых демонстрирует этот пост, это использование Build.scala с одним проектом.
Наш пример — это простое консольное приложение Spring с парой тестовых примеров JUnit : этого достаточно, чтобы увидеть, как строится сборка с внешними зависимостями и выполняются тесты. Приложение содержит только два класса:
package com.example; import org.springframework.stereotype.Service; @Service public class SimpleService { public String getResult() { return "Result"; } }
и
package com.example; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.support.GenericApplicationContext; public class Starter { @Configuration @ComponentScan( basePackageClasses = SimpleService.class ) public static class AppConfig { } public static void main( String[] args ) { try( GenericApplicationContext context = new AnnotationConfigApplicationContext( AppConfig.class ) ) { final SimpleService service = context.getBean( SimpleService.class ); System.out.println( service.getResult() ); } } }
Теперь давайте посмотрим, как выглядит сборка sbt . По договоренности Build.scala должен находиться в подпапке проекта . Кроме того, должен присутствовать файл build.properties с желаемой версией sbt и plugins.sbt с внешними плагинами (мы будем использовать плагин sbteclipse для генерации файлов проекта Eclipse ). Начнем с build.properties, который содержит только одну строку:
sbt.version=0.13.1
и продолжим с plugins.sbt , который в нашем случае тоже всего одна строка:
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.4.0")
Наконец, давайте начнем с сердца нашей сборки: Build.scala . В нем будет две части: общие настройки для всех проектов в нашей сборке (полезно для многопроектных сборок, но сейчас у нас есть только одна), и вот фрагмент этой части:
import sbt._ import Keys._ import com.typesafe.sbteclipse.core.EclipsePlugin._ object ProjectBuild extends Build { override val settings = super.settings ++ Seq( organization := "com.example", name := "sbt-java", version := "0.0.1-SNAPSHOT", scalaVersion := "2.10.3", scalacOptions ++= Seq( "-encoding", "UTF-8", "-target:jvm-1.7" ), javacOptions ++= Seq( "-encoding", "UTF-8", "-source", "1.7", "-target", "1.7" ), outputStrategy := Some( StdoutOutput ), compileOrder := CompileOrder.JavaThenScala, resolvers ++= Seq( Resolver.mavenLocal, Resolver.sonatypeRepo( "releases" ), Resolver.typesafeRepo( "releases" ) ), crossPaths := false, fork in run := true, connectInput in run := true, EclipseKeys.executionEnvironment := Some(EclipseExecutionEnvironment.JavaSE17) ) }
Вышеприведенная сборка выглядит довольно чистой и понятной: resolvers — это прямая аналогия репозиториев Apache Maven , EclipseKeys.executionEnvironment — это настройка среды выполнения (Java SE 7) для сгенерированного проекта Eclipse . Все эти ключи очень хорошо документированы .
Вторая часть намного меньше и определяет наш основной проект с точки зрения зависимостей и основного класса:
lazy val main = Project( id = "sbt-java", base = file("."), settings = Project.defaultSettings ++ Seq( mainClass := Some( "com.example.Starter" ), initialCommands in console += """ import com.example._ import com.example.Starter._ import org.springframework.context.annotation._ """, libraryDependencies ++= Seq( "org.springframework" % "spring-context" % "4.0.0.RELEASE", "org.springframework" % "spring-beans" % "4.0.0.RELEASE", "org.springframework" % "spring-test" % "4.0.0.RELEASE" % "test", "com.novocode" % "junit-interface" % "0.10" % "test", "junit" % "junit" % "4.11" % "test" ) ) )
В initialCommands требует немного объяснения здесь: SBT может работать Scala консоль (REPL) и этот параметр позволяет добавлять стандартные операторы импорта , поэтому мы можем использовать наши занятия сразу. Зависимость от junit-интерфейса позволяет sbt запускать тестовые случаи JUnit, и это первое, что мы сделаем: добавим несколько тестов. Перед созданием реальных тестов мы запустим sbt и попросим его запускать тестовые примеры при каждом изменении кода, вот так:
sbt ~test
Пока sbt работает, мы добавим тестовый пример:
package com.example; import static org.hamcrest.core.IsEqual.equalTo; import static org.junit.Assert.assertThat; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.support.GenericApplicationContext; import com.example.Starter.AppConfig; public class SimpleServiceTestCase { private GenericApplicationContext context; private SimpleService service; @Before public void setUp() { context = new AnnotationConfigApplicationContext( AppConfig.class ); service = context.getBean( SimpleService.class ); } @After public void tearDown() { context.close(); } @Test public void testSampleTest() { assertThat( service.getResult(), equalTo( "Result" ) ); } }
В консоли мы должны увидеть, что sbt автоматически выбрал изменение и запустил все тестовые случаи. К сожалению, из-за этой проблемы, которая уже исправлена и должна быть доступна в следующей версии junit-интерфейса , мы не можем пока использовать аннотации @RunWith и @ContextConfiguration для запуска тестовых случаев Spring .
Для практиков TDD это потрясающая возможность. Следующая потрясающая функция, которую мы собираемся рассмотреть, это консоль Scala (RELP), которая дает возможность играть с приложением, фактически не запуская его. Это может быть вызвано, набрав:
sbt console
и наблюдаем что-то подобное в терминале (как мы видим, импорт из initialCommands автоматически включается):
На данный момент игровая площадка создана, и мы можем сделать много очень интересных вещей, например: создать контекст, получить bean-компоненты и вызвать любые методы для них:
sbt заботится о classpath, поэтому все ваши классы и внешние зависимости доступны для использования. Я нашел этот способ обнаружить вещи намного быстрее, чем с помощью отладчика или других методов.
На данный момент в Eclipse нет хорошей поддержки sbt, но очень просто генерировать файлы проекта Eclipse с помощью плагина sbteclipse, к которому мы обращались ранее:
sbt eclipse
Потрясающие! Не говоря уже о других замечательных плагинах, которые любезно перечислены здесь, и о возможности импортировать POM-файлы Apache Maven с помощью externalPom (), который действительно упрощает миграцию. В заключение, с моей стороны, если вы ищете лучший, современный, расширяемый инструмент для сборки вашего проекта, пожалуйста, посмотрите на sbt . Это отличный кусок программного обеспечения, созданного на основе удивительного, продуманного языка.
Полный проект доступен на GitHub .