Java development 2.0: Вторая волна разработки Java-приложений: Создание сверхлегковесных Web-сервисов Java с помощью Gretty

Gretty исключает Web-стек и реально ускоряет разработку приложений

Gretty относится к сверхлегковесным инфраструктурам нового типа, предназначенным для создания Web-сервисов. Построенная поверх удивительно быстрых интерфейсов для программирования приложений Java™ NIO, Gretty использует Groovy в качестве предметно-ориентированного языка для разработки конечных Web-точек и управления зависимостями в стиле Grape Maven. В этой статье рассказывается, как использовать Gretty для создания и развертывания Web-сервисов на языке Java.

Эндрю Гловер, президент компании, Stelligent Incorporated

Эндрю ГловерЭндрю Гловер является президентом компании Stelligent Incorporated , которая помогает другим фирмам решать проблемы качества программного обеспечения. Для этого используются эффективные стратегии тестирования и технологии непрерывной интеграции, которые позволяют коллективам разработчиков постоянно контролировать качество кода, начиная с ранних стадий разработки. Просмотрите блог Энди , там можно найти список его публикаций.



04.07.2012

На протяжении нескольких статей серии Java development 2.0 я использовал в качестве примера простое облачное приложение для работы с мобильными телефонами. Это приложение, названное мною Magnus, выступает в роли конечной точки HTTP, собирающей информацию о местоположении мобильных телефонов. Его работа основана на получении запросов HTTP PUT, каждый из которых содержит документ JSON, указывающий на местоположение зарегистрированного пользователя в данный момент времени. До сих пор для создания и расширения Magnus я использовал интегрированную среду Play (см. Ресурсы).

Об этой серии

С момента первого появления технологии Java™ принципы разработки ПО на этом языке претерпели значительные изменения. Благодаря появлению мощных систем с открытым исходным кодом и надежных инфраструктур для предоставления средств разработки в аренду стало возможным быстро и дешево собирать, тестировать, исполнять и поддерживать приложения Java. В данной серии статейЭндрю Гловер описывает широкий спектр средств и технологий, благодаря которым стала возможной эта новая парадигма разработки на языке Java.

Интегрированная среда Play напоминает Grails в том смысле, что предлагает стек MVC. Play позволяет легко определить контроллеры (сервлеты), использующие представления (JSP, GSP, шаблоны и т.п.), которые некоторым образом манипулируют моделями. Модели реализуются с помощью POJO (простых объектов Java), дополненных Hibernate, JPA или другими модными ORM-подобными технологиями.

Хотя подход MVC существует уже давно, с приходом интегрированных сред типа Grails и Play многое изменилось. Вспомните, каких усилий стоило когда-то создание простого Web-взаимодействия типа запрос-ответ — скажем, с помощью Struts, — и вы поймете, как далеко мы продвинулись к быстрому созданию Web-приложений на основе MVC. И все же не всем Web-приложениям нужна для работы инфраструктура MVC. Некоторым современным Web-приложениям "стек" MVC вообще не нужен.

Прежде чем закрыть браузер в знак протеста против столь еретического утверждения, вспомните о Magnus. Хотя это приложение создано исключительно для целей демонстрации, оно не содержит традиционного компонента представления и большей частью состоит из существующих и успешно работающих сервисов. Подобно Twitter или Foursquare, Magnus принимает сообщения от разных устройств, разбросанных по всему миру. В широком смысле слова Magnus представляет собой Web-сервис, и не каждому Web-сервису для работы нужен стек MVC. В некоторых случаях вам понадобится всего лишь сверхлегковесная Web-система без Web-стека.

В этом месяце мы рассмотрим вот что: интегрированную среду для быстрой разработки, настолько новую, что у нее даже нет собственного сайта, и, вероятно, он ей и не нужен. Происхождение и родственные связи Gretty (включая соответственно Netty и Groovy) настолько респектабельны, чтобы открыть ей путь в семейство средств разработки Web-приложений Java 2.0. Gretty нацелена на удовлетворение потребности, о существовании которой многие разработчики еще даже не догадываются (это в стиле Web 2.0, не так ли?). И она достаточно стабильна для промышленного применения, — если вы готовы рискнуть.

История быстрого развития Java

Те из нас, кто еще помнит первое появление API Servlets, вправе скептически относиться к новой концепции "легковесности"; ведь в конце концов даже простой сервлет позволяет создать Web-сервис без серьезного программирования и последующих файлов JAR. Интегрированные среды для создания Web-сервисов, такие как Restlet или Jersey, исповедуют несколько иной подход к скорости разработки, используя расширения классов, аннотации и даже стандартные JSR для создания Web-сервисов RESTful. При этом оба они достаточно хороши для некоторых сценариев.

Но тут выясняется, что некоторые новые легковесные интегрированные среды (в противоположность старым легковесным) позволяют удивительно просто определять Web-сервисы или простые конечные точки HTTP. Это даже проще, чем ручная сборка сервлета!

Изначально эти интегрированные среды появились на других платформах, например, Sinatra для Ruby и Express для Node.js. Но затем стали появляться интересные проекты и для платформы Java. Один из них — Gretty, который, конечно, предназначен для Groovy и JVM.


Я за Gretty

Лично для меня Gretty имеет как минимум два преимущества: во-первых, она использует Groovy Grape (который я вскоре опишу более подробно), чтобы облегчить управление зависимостями. Во-вторых, она предлагает простой DSL-подобный синтаксис для определения конечных точек. Gretty позволяет очень быстро (всего несколькими короткими строчками кода) определить и развернуть работающую Web-систему, которая выполняет все необходимые операции. В качестве примера взгляните на пример канонической программы «Hello World», который я слепил на скорую руку в листинге 1:

Листинг 1. Hello World: это Gretty!
import org.mbte.gretty.httpserver.* 

@GrabResolver(name='gretty', 
  root='http://groovypp.artifactoryonline.com/groovypp/libs-releases-local')
@Grab('org.mbte.groovypp:gretty:0.4.279') 

GrettyServer server = [] 
server.groovy = [ 
    localAddress: new InetSocketAddress("localhost", 8080), 
    defaultHandler: { 
        response.redirect "/" 
    }, 
    "/:name": {
        get {
            response.text = "Hello ${request.parameters['name']}"
        } 
    } 
] 
server.start()

В листинге 1 я создал сервер, слушающий порт 8080, а затем создал простую корневую конечную точку, содержащую параметр name (имя). Любой запрос к другой конечной точке будет перенаправлен назад на / через defaultHandler. Обработчик обычно отправляет запрашивающему клиенту код HTTP 301 "Перемещено навсегда" с местоположением /. На все запросы будут поступать ответы (с типом контента, установленным на text/plain), содержащие строку "Hello" и значение любого переданного параметра; например, /Andy получит ответ "Hello Andy."

Gretty и NIO

Gretty была создана с помощью Netty — клиент-серверной инфраструктуры разработки, интенсивно использующей библиотеки NIO языка Java. Пакет библиотек ввода/вывода NIO (или New I/O), был представлен достаточно давно, с выходом версии Java 1.4. В основном NIO интересен своими неблокирущими операциями ввода/вывода, что позволяет создавать масштабируемые серверы. Эта возможность удобно реализуется в интегрированных средах, подобных Netty и Gretty.

Чем интересен листинг 1? Первое и самое главное — того, что вы видите в листинге, вполне достаточно для создания приложения, — и не нужно никаких конфигурационных файлов. Мне не нужно непосредственно что-то загружать или устанавливать (в отличие от Groovy 1.8). Чтобы запустить этот пример, я просто набрал groovy server.groovy.

Но что если ваш ответ должен быть сложнее простого текста? Для этого Gretty предлагает множество возможностей, две из которых достаточно просты. Во-первых, можно просто установить тип ответа на HTML, как я сделал в листинге 2:

Листинг 2. Ответы HTML в Gretty
"/:name": {
 get {
  response.html = "Hello ${request.parameters['name']}"
 } 
}

В этом случае тип содержимого ответа должен быть установлен на text/html. В качестве альтернативы Gretty позволяет использовать статические и динамические шаблоны. Например, я могу определить шаблон с помощью простой JSP/GSP-подобной конструкции, как в листинге 3:

Листинг 3. Шаблон HTML в Gretty
<html>
 <head>
  <title>Hello!</title>
 </head>
 <body>
  <p>${message}</p>
 </body>
</html>

Затем я могу сослаться на шаблон в теле ответа:

Листинг 4. Шаблон Groovy++ в Gretty
"/:name" {
  get {
   response.html = template("index.gpptl", 
     [message: "Hello ${request.parameters['name']}"])
  }
}

Управление зависимостями с помощью Gretty и Grape

Отчасти впечатляющая скорость разработки в Gretty достигается благодаря Grape (см. Ресурсы), который используется для автоматической загрузки двоичных зависимостей или файлов JAR. Все файлы загружаются с транзитивными зависимостями в стиле Maven. Все, что мне нужно сделать в листинге 1, — это добавить аннотацию @Grab('org.mbte.groovypp:gretty:0.4.279'), и я получу файл JAR, связанный с Gretty, вместе с зависимостями Gretty. Аннотация @GrabResolver(name='gretty', root='http://groovypp.artifactoryonline.com/groovypp/libs-releases-local') показывает, где Grape может найти необходимые файлы.

Gretty — это не просто Groovy

Gretty не ограничивается языком Groovy. Как во всех инфраструктурах, работающих на JVM, в Gretty можно писать приложения на Java или даже на Scala.

Как ни просто выглядит Grape, это не значит, что он не пригоден для производства. На самом деле используемая в Grape автоматическая загрузка зависимостей не сильно отличается от Maven. Просто она выполняется во время исполнения при первом запуске приложения, тогда как Maven загружает необходимые зависимости во время сборки. Если Grape сможет найти необходимые зависимости локально, то загрузка вообще не потребуется. Необходимые файлы JAR автоматически помещаются в classpath приложения. В результате вы теряете в производительности лишь при первом запуске настроенного в Grape приложения. Конечно, производительность немного падает при каждом изменении необходимой версии указанной зависимости.


Gretty встречается с Magnus

Надеюсь, теперь вы поняли, что Gretty проста и позволяет легко и быстро разрабатывать серьезные приложения. К тому же Gretty (и подобные ей интегрированные среды) идеально подходит для таких приложений, как Magnus, — прослушивающих конечные точки HTTP в ожидании данных. Давайте взглянем, что получится, если полностью заменить довольно легковесную интегрированную среду типа Play или Grails еще более легковесным приложением, написанным с помощью Gretty.

Для этой инкарнации Magnus я использую Morphia и MongoHQ, которые вы, вероятно, помните из моего введения в Amazon Elastic Beanstalk. Чтобы использовать утилиту Grape из Groovy с новой конфигурацией, мне понадобится добавить аннотацию к моему серверу в листинге 5:

Листинг 5. Добавление Morphia и его зависимостей
@GrabResolver(name='morphia', root='http://morphia.googlecode.com/svn/mavenrepo/')
@Grab(group='com.google.code.morphia', artifactId='morphia', module="morphia", 
  version='0.99')

Мои классы Morphia те же, что и в прежней инкарнации Magnus: я по-прежнему имею Account (учетную запись) и Location (местоположение). В этой конечной точке я просто обновляю местоположение для данной учетной записи. Поскольку клиенты Morphia будут отправлять документы JSON в конечную точку Gretty, я собираюсь использовать Jackson, замечательную систему обработки JSON, которая уже входит в состав Gretty. Благодаря тому, что Grape обрабатывает транзитивные зависимости, я получаю доступ ко всему, что мне нужно для разборки входящего документа JSON и преобразования его в простую карту Java Map.

Листинг 6. Обновление местоположений в Gretty
def server = new GrettyServer().localAddress(new InetSocketAddress("localhost", 8080)).
 "/location/:account" {
  put {
    def jacksonMapper = new ObjectMapper()
    def json = jacksonMapper.readValue(request.contentText, Map.class)
    def formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm")
    def dt = formatter.parse(json['timestamp'])
    def res = [:]
    try{
      new Location(request.parameters['account'], dt, json['latitude'].doubleValue() , 
          json['longitude'].doubleValue() ).save()
	  res['status'] = 'success'
    }catch(exp){
      res['status'] = "error ${exp.message}"
    }
    response.json = jacksonMapper.writeValueAsString(res)
  }
}
server.start ()

Как видно в листинге 6, Map входящего документа JSON создается (дублированием json) и затем соответствующим образом вставляется в MongoDB через мой класс Location в листинге 7:

Листинг 7. Создание документа с местоположениями — Gretty возвращается
import com.google.code.morphia.annotations.Entity

@Entity(value = "locations", noClassnameStored = true)
class Location extends AbstractModel {
 String accountId
 double latitude
 double longitude
 Date timestamp

 public Location(String accountId, Date timestamp, double lat, double lon) {
  this.accountId = accountId
  this.timestamp = timestamp
  this.latitude = lat
  this.longitude = lon
 }
}

И более того, мое местоположение Location имеет суперкласс Groovy, как показано в листинге 8:

Листинг 8. Базовый класс местоположения
import com.google.code.morphia.Morphia
import com.google.code.morphia.annotations.Id
import com.mongodb.Mongo
import org.bson.types.ObjectId

abstract class AbstractModel {
  @Id
  private ObjectId id;

  def save() throws Exception {
    def mongo = new Mongo("fame.mongohq.com", 32422)
    def datastore = new Morphia().createDatastore(mongo, "xxxx", 
      "xxxx", "xxxx".toCharArray())
    datastore.save(this)
    return this.id
  }
}

Возможно, вы помните этот код из листинга 3 статьи "Восхождение на Elastic Beanstalk." Единственным изменением, которое я внес в реализацию Gretty, было переименование файла Location.java в Location.groovy для того, чтобы не пришлось компилировать его перед запуском сервера. Кроме того, я добавил базовый класс. Местоположение привязывается к учетной записи через входящий параметр account, полученный из URI.

Затем в JSON отправляется ответ, означающий успешное выполнение. В случае ошибки будет отправлен другой ответ.


Заключение: Gretty готова к работе

Инфраструктура Gretty настолько легковесна, насколько это вообще возможно. В ней нет встроенной системы ORM. В ней нет инфраструктуры представлений, кроме простых шаблонов, но зато вполне возможно подключение других инфраструктур. Означает ли это, что Gretty еще не готова для повседневного применения? Может быть, отсутствие системы отладки тоже на это намекает? Ответом будет «нет»: во-первых, Gretty опирается на проверенный код Netty, поэтому вы сразу же получаете некоторые гарантии. Во-вторых, вы можете тестировать Gretty так же, как вы делали бы это с любой другой конечной Web-точкой, будь то автоматически или нет. На самом деле если вы хотите узнать, как тестируется Gretty, загляните в ее исходный код, — там найдется достаточно тестов!

Gretty — полная противоположность современным полностековым Web- инфраструктурам, именно потому, что часто полный стек вообще не нужен. Если вы обнаружите, что система, подобная Gretty, требует от вас слишком больших трудозатрат, то вам, вероятно, лучше обратиться к одной из многих полностековых и хорошо документированных Web-инфраструктур Java. Аналогично, если вы поймете, что вам не нужен полный стек для обработки запросов и ответов Web-сервисов, то Gretty вам отлично подойдет.

Ресурсы

Научиться

Получить продукты и технологии

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Технология Java, Open source
ArticleID=824144
ArticleTitle=Java development 2.0: Вторая волна разработки Java-приложений: Создание сверхлегковесных Web-сервисов Java с помощью Gretty
publish-date=07042012