Руководство по сальто на весну

Руководство по сальто на весну

1. обзор

В этом руководстве мы рассмотримFlips, библиотеку, которая реализует флаги функций в виде мощных аннотаций для приложений Spring Core, Spring MVC и Spring Boot.

Флаги функций (или переключатели) - это шаблон для быстрой и безопасной доставки новых функций. Эти переключатели позволяют нам изменять поведение приложенияwithout changing or deploying new code. В блоге Мартина Фаулера есть очень информативная статья о флагах функцийhere.

2. Maven Dependency

Прежде чем мы начнем, нам нужно добавить библиотеку Flips в нашpom.xml:


    com.github.feature-flip
    flips-core
    1.0.1

Maven Central имеетlatest version of the library, а проект Github -here.

Конечно, нам также нужно включить Spring:


    org.springframework.boot
    spring-boot-starter-web
    1.5.10.RELEASE

Поскольку Flips еще не совместим со Spring версии 5.x, мы собираемся использоватьlatest version of Spring Boot in the 4.x branch.

3. Простая служба REST для флипов

Давайте соберем простой проект Spring Boot для добавления и переключения новых функций и флагов.

Наше приложение REST предоставит доступ к ресурсамFoo:

public class Foo {
    private String name;
    private int id;
}

Мы просто создадимService, который поддерживает списокFoos:

@Service
public class FlipService {

    private List foos;

    public List getAllFoos() {
        return foos;
    }

    public Foo getNewFoo() {
        return new Foo("New Foo!", 99);
    }
}

Мы будем обращаться к дополнительным методам обслуживания по мере продвижения, но этого фрагмента должно быть достаточно, чтобы проиллюстрировать, чтоFlipService делает в системе.

И, конечно же, нам нужно создать контроллер:

@RestController
public class FlipController {

    private FlipService flipService;

    // constructors

    @GetMapping("/foos")
    public List getAllFoos() {
        return flipService.getAllFoos();
    }
}

4. Функции управления в зависимости от конфигурации

Основное использование Flips - включение или отключение функции в зависимости от конфигурации. Flips имеет несколько аннотаций для этого.

4.1. Свойство окружающей среды

Представим, что мы добавили новую возможность вFlipService; получениеFoos по их идентификатору.

Добавим в контроллер новый запрос:

@GetMapping("/foos/{id}")
@FlipOnEnvironmentProperty(
  property = "feature.foo.by.id",
  expectedValue = "Y")
public Foo getFooById(@PathVariable int id) {
    return flipService.getFooById(id)
      .orElse(new Foo("Not Found", -1));
}

@FlipOnEnvironmentProperty определяет, доступен ли этот API.

Проще говоря, когдаfeature.foo.by.id равноY, мы можем делать запросы по Id. Если он не задан (или не определен вообще), Flips отключит метод API.

Если функция не включена, Flips выдастFeatureNotEnabledException, а Spring вернет клиенту REST значение «Не реализовано».

Когда мы вызываем API со свойством, установленным наN, мы видим следующее:

Status = 501
Headers = {Content-Type=[application/json;charset=UTF-8]}
Content type = application/json;charset=UTF-8
Body = {
    "errorMessage": "Feature not enabled, identified by method
      public com.example.flips.model.Foo
      com.example.flips.controller.FlipController.getFooById(int)",
    "className":"com.example.flips.controller.FlipController",
    "featureName":"getFooById"
}

Как и ожидалось, Spring перехватываетFeatureNotEnabledException и возвращает статус 501 клиенту.

4.2. Активный профиль

Spring уже давно дает нам возможность отображать bean-компоненты в разныеprofiles, такие какdev,test илиprod. Расширение этой возможности для отображения флагов функций в активный профиль имеет интуитивный смысл.

Давайте посмотрим, как функции включаются или отключаются в зависимости от активногоSpring Profile:

@RequestMapping(value = "/foos", method = RequestMethod.GET)
@FlipOnProfiles(activeProfiles = "dev")
public List getAllFoos() {
    return flipService.getAllFoos();
}

Аннотация@FlipOnProfiles принимает список имен профилей. Если активный профиль находится в списке, API доступен.

4.3. Весенние выражения

Spring’s Expression Language (SpEL) - мощный механизм для управления средой выполнения. Flips также позволяет нам переключать функции.

@FlipOnSpringExpression переключает метод на основе выражения SpEL, которое возвращает логическое значение.

Давайте воспользуемся простым выражением для управления новой функцией:

@FlipOnSpringExpression(expression = "(2 + 2) == 4")
@GetMapping("/foo/new")
public Foo getNewFoo() {
    return flipService.getNewFoo();
}

4.4. Отключить

Чтобы полностью отключить функцию, используйте@FlipOff:

@GetMapping("/foo/first")
@FlipOff
public Foo getFirstFoo() {
    return flipService.getLastFoo();
}

В этом примереgetFirstFoo() полностью недоступен.

Как мы увидим ниже, мы можем комбинировать аннотации Flips, что позволяет использовать@FlipOff для отключения функции в зависимости от среды или других критериев.

5. Функции управления с помощью даты / времени

Сальто может переключать функцию на основе даты / времени или дня недели. Привязка доступности новой функции ко дню или дате имеет очевидные преимущества.

5.1. Дата и время

@FlipOnDateTime принимает имя свойства, отформатированное в форматеISO 8601.

Итак, давайте установим свойство, указывающее на новую функцию, которая будет активна 1 марта:

first.active.after=2018-03-01T00:00:00Z

Затем мы напишем API для получения первого Foo:

@GetMapping("/foo/first")
@FlipOnDateTime(cutoffDateTimeProperty = "first.active.after")
public Foo getFirstFoo() {
    return flipService.getLastFoo();
}

Flips проверит указанное свойство. Если свойство существует и указанные дата / время прошли, функция включена.

5.2. День недели

Библиотека предоставляет@FlipOnDaysOfWeek, который полезен для таких операций, как A / B-тестирование:

@GetMapping("/foo/{id}")
@FlipOnDaysOfWeek(daysOfWeek={DayOfWeek.MONDAY, DayOfWeek.WEDNESDAY})
public Foo getFooByNewId(@PathVariable int id) {
    return flipService.getFooById(id).orElse(new Foo("Not Found", -1));
}

getFooByNewId() доступен только по понедельникам и средам.

6. Заменить фасоль

Включение и выключение методов полезно, но мы можем захотеть представить новое поведение через новые объекты. @FlipBean указывает Flips вызвать метод в новом компоненте.

Аннотация Flips может работать с любым Spring@Component.. Пока что мы изменили только наш@RestController, давайте попробуем изменить нашService.

Мы создадим новый сервис с поведением, отличным отFlipService:

@Service
public class NewFlipService {
    public Foo getNewFoo() {
        return new Foo("Shiny New Foo!", 100);
    }
}

Мы заменимgetNewFoo() старой службы на новую версию:

@FlipBean(with = NewFlipService.class)
public Foo getNewFoo() {
    return new Foo("New Foo!", 99);
}

Flips направит вызовыgetNewThing() наNewFlipService. @FlipBean - еще один переключатель, который наиболее полезен в сочетании с другими. Давайте посмотрим на это сейчас.

7. Комбинирование переключателей

Мы объединяем переключатели, указав более одного. Flips оценивает их последовательно, с неявной логикой «И». Поэтому все они должны быть верны, чтобы включить эту функцию.

Давайте объединим два наших предыдущих примера:

@FlipBean(
  with = NewFlipService.class)
@FlipOnEnvironmentProperty(
  property = "feature.foo.by.id",
  expectedValue = "Y")
public Foo getNewFoo() {
    return new Foo("New Foo!", 99);
}

Мы воспользовались новой настраиваемой службой.

8. Заключение

В этом кратком руководстве мы создали простой сервис Spring Boot и включали и выключали API с помощью аннотаций Flips. Мы увидели, как функции переключаются с использованием информации о конфигурации и даты / времени, а также как функции можно переключать, меняя компоненты во время выполнения.

Примеры кода, как всегда, можно найтиover on GitHub.