Показаны сообщения с ярлыком Аннотации. Показать все сообщения
Показаны сообщения с ярлыком Аннотации. Показать все сообщения

четверг, 30 июля 2015 г.

Spring Boot на примере простого REST-сервиса

Последние пару месяцев я активно изучаю Spring Boot и перевожу некоторые из своих проектов на эту архитектуру. В этом посте я в кратце опишу создание простого приложения на Spring Boot.

Стартеры и зависимости

Разработчики Spring Boot постарались по максимуму уменьшить время, уходящее на конфигурирование проекта, добавив в Maven артефакты spring-boot-starter-* из группы org.springframework.boot. По сути это зависимости, которые тянут за собой остальные зависимости, необходимые для разработки приложения нужного типа. Подробнее со списком доступных стартеров можно ознакомиться в официальной документации по Spring Boot.

Хотя, если вы хотите самостоятельно указывать используемые зависимости, можно не использовать стартеры, а указать в зависимостях артефакт spring-boot-autoconfigure из org.springframework.boot. Но в целом стартеры очень удобны.

Приложение

В данном примере я буду использовать единственную зависимость:
<dependencies>
    <dependency>
        <groupid>org.springframework.boot</groupid>
        <artifactid>spring-boot-starter-web</artifactid>
        <version>1.2.5.RELEASE</version>
    </dependency>
</dependencies> 
Она за собой потянет всё необходимое для написания простого веб-приложения.

Так как это standalone-приложение, нам потребуется стадартый класс с методом main:
package name.alexkosarev.sandbox.springboot.rest;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args).registerShutdownHook();
    }
}
В данном случае аннотация @SpringBootApplication заменяет собой аннотации @Configuration, @EnableAutoConfiguration и @ComponentScan.

В моём примере REST-сервис будет возвращать объект простого класса, в котором будет текстовое сообщение:

package name.alexkosarev.sandbox.springboot.rest.wrappers;

public class MessageWrapper {

    private String message;

    public MessageWrapper() {
    }

    public MessageWrapper(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

}

Теперь нужно добавить контроллер, который будет обрабатывать запрос и возвращать ответ:
package name.alexkosarev.sandbox.springboot.rest.services;

import name.alexkosarev.sandbox.springboot.rest.wrappers.MessageWrapper;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/example")
public class ExampleService {

    @RequestMapping
    public MessageWrapper index() {
        return new MessageWrapper("Hello world!");
    }
}

Аннотация @RestController комбинирует в себе @Controller и @ResponseBody, указывая, что данный контроллер является REST-контроллером и возвращаемые значения методов данного класса, помеченных аннотацией @RequestMapping, будут ответами на HTTP-запросы.

Теперь можно запустить приложение и открыть адрес http://localhost:8080/example. В ответ будет выведено {"message":"Hello world!"}.

МегаJAR

Это конечно, круто, скажите вы, но теперь у нас есть JAR с приложением и горстка JAR с зависимостями. Можно ли как-то с этим бороться? Да, можно. Разработчики Spring предлагают 2 варианта решения данной проблемы:
  1. Поместить все JAR зависимостей в директорию lib внутри JAR проекта, что не очень правильно
  2. Добавить в Maven-плагин spring-boot-maven-plugin из группы org.springframework.boot с целью repackage, в результате чего в директории target будет лежать 2 JAR: обычный и толстый, в который будут скопировано содержимое всех JAR зависимостей.
<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <version>1.2.5.RELEASE</version>
    <executions>
        <execution>
   <goals>
       <goal>repackage</goal>
   </goals>
        </execution>
    </executions>
</plugin>

Spring Framework, Hibernate, JPA: Аннотации или XML?

Споры на данную тему в стане приверженцев Spring Framework существуют с момента релиза третьей версии данного фреймворка. И хотя в версии 2.5 уже можно было частично заменить конфигурирование приложения аннотациями, полностью отказаться от XML было нереально.

Оба подхода имеют свои плюсы и минусы, и на мой взгляд, если нет возможости выбрать какой-то конкретный, то логично использовать их вместе.

Стоит отметить забавный момент, что среди разработчиков фреймворка во время Spring Framework 3 не было единого мнения по этому поводу - в книге Pro Spring 3 использовались XML-конфигурации, а в книге Pro Spring MVC: with Web Flow - аннотации.

XML

С XML-конфигурациями в Spring Framework я работаю ещё с версии 2.5. На тот момент альтернатив не было. Зато можно было хотя бы использовать аннотацию @Autowired для внедрения зависимостей, чему я предпочитал непосредственное указание зависимостей в XML через сеттеры и конструкторы. С тех пор я унаследовал привычку конфигурировать практически всё при помощи XML, в том числе JPA и Hibernate. Для меня главным аргументом в пользу XML была возможность изменять настройки приложения на лету без необходимости собирать проект заново. Такая необходимость возникала, но нечасто. Хотя объективности ради стоит заметить, что именяющиеся компоненты Spring-приложения вполне можно конфигурировать properties-файлами или через JNDI.

Против XML главным аргументом всегда являлся тот факт, что в больших проектах XML-конфигурацию очень сложно читать ввиду большого количества конфигурируемых компонентов и нередко большого количества файлов конфигурации. В качестве примера можно привести проекты CMDBuild и OpenOLAT.

Актуальность XML-конфигураций теряется ещё и в том случае, когда разработчик не имеет физического доступа к развёрнутому приложению, как это зачастую бывает в серьёзных организациях. Именно это и стало для меня решающим фактором в пользу перехода на использование аннотаций.


Аннотации

В пользу аннотаций можно однозначно записать простоту. Конфигурирование приложения посредством аннотаций происходит проще, чем при использовании XML. Всё делается тем же Java-кодом. Разработчику в данном случае даже не обязательно знать XML, хотя я сильно сомневаюсь, что в природе существуют Java-разработчики без базовых знаний XML.

Отдельно стоит отметить тот факт, что в мире Java EE всё давно конфигурируется при помощи аннтоаций: EJB, CDI, JPA и т.д. и Spring Framework совместим со всеми аннотациями Java EE.

Ну а минус, соответственно, заключается в отсутствии возможности конфигурировать проект на лету.

Groovy

Отдельно стоит упомянуть возможность конфигурировать Spring-приложения при помощи Groovy-классов. Если классы конфигурации не компилировать, а оставлять скриптами, то приложение можно будет конфигурировать на лету. И при этом сам процесс конфигурирования будет значительно более гибким, чем даже при использовании XML. Но это если в проекте используется Groovy.

Вывод

Вывод прост - нужно стремиться к использованию аннотаций, раз это действительно проще, правильнее и рекомендуется разработчиками Spring Framework. Тем более, что в Java EE это стандарт, а на горизонте маячит Spring Boot, хотя никто не запрещает и там использовать XML.

Однако в плане маппингов JPA и Hibernate я так и остался при мнении, что использование XML значительно удобнее аннотаций, особенно в случаях, когда POJO-классы находятся в отдельной от бизнес-логики библиотеке. В этом случае клиентским Java-приложениям при использовании тех же API не нужно будет тянуть ненужные зависимости.