Я думаю, что для разработчиков выбор правильного инструмента сборки — очень важный выбор. В течение многих лет я придерживался 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 .