1. Введение
В этой статье мы сосредоточимся на интеграции Akka с Spring Framework – чтобы позволить инъекции весенних услуг в актеров Акка.
Перед чтением этой статьи рекомендуется предварительное знание основ Акки.
Дальнейшее чтение:
Знакомство с актерами Акка на Яве
Путеводитель по Акка-Стримы
2. Инъекция зависимости в Акке
Акка является мощной рамкой приложения, основанной на модели concurrency Actor. Фреймвейт написан в Scala, что, конечно, делает его полностью годным к применению в Java-приложениях. И так очень часто мы хотим интегрировать Akka с существующим приложением на основе весны, которое или просто использовать весна для проводки бобов в актеров.
Проблема интеграции Весна/Акка заключается в разнице между управлением бобами весной и управлением актерами в Акке: актеры имеют определенный жизненный цикл, который отличается от типичного жизненного цикла весенних бобов .
Кроме того, актеры делятся на самого актера (что является внутренней деталью реализации и не может управляться Spring) и ссылку актера, которая доступна по коду клиента, а также сериализируемой и портативной между различными периодами выполнения Akka.
К счастью, Akka предоставляет механизм, а именно Акка расширения , что делает использование внешних структур впрыска зависимости довольно легкой задачей.
3. Maven зависимостей
Чтобы продемонстрировать использование Akka в нашем весеннем проекте, нам понадобится минимальная зависимость от весны – весенне-контекстный библиотеки, а также Акка-актер библиотека. Версии библиотеки могут быть извлечены в
4.3.1.RELEASE 2.4.8 org.springframework spring-context ${spring.version} com.typesafe.akka akka-actor_2.11 ${akka.version}
Убедитесь в том, чтобы проверить Maven Central для последних версий весенне-контекстный и Акка-актер Зависимости.
И заметьте, как, что Акка-актер зависимость имеет 2,11 postfix в своем названии, что означает, что эта версия фреймворка Akka была построена против версии Scala 2.11. Соответствующая версия библиотеки Scala будет временно включена в вашу сборку.
4. Инъекционные весенние бобы в Акка Актеры
Давайте создадим простое приложение Весна/Акка, состоящее из одного актера, который может ответить на имя человека, выдав приветствие этому человеку. Логика приветствия будет извлечена в отдельную службу. Мы хотим, чтобы autowire эту услугу актера экземпляра. Весенняя интеграция поможет нам в этой задаче.
4.1. Определение актера и службы
Чтобы продемонстрировать вливание службы в актера, мы создадим простой класс ПриветствиеАктор определяется как нетипийный актер (расширение UntypedActor базового класса). Основным методом каждого актера Акка является onReceive метод, который получает сообщение и обрабатывает его в соответствии с определенной логикой.
В нашем случае ПриветствиеАктор реализация проверяет, имеет ли сообщение предопределенный тип Приветствуйте , затем берет имя человека из Приветствуйте например, затем использует Поздравительная служба получить приветствие для этого человека и ответы отправителя с полученной строкой приветствия. Если сообщение имеет какой-либо другой неизвестный тип, оно передается в предопределенную неохвоженные метод.
Давайте посмотрим:
@Component @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class GreetingActor extends UntypedActor { private GreetingService greetingService; // constructor @Override public void onReceive(Object message) throws Throwable { if (message instanceof Greet) { String name = ((Greet) message).getName(); getSender().tell(greetingService.greet(name), getSelf()); } else { unhandled(message); } } public static class Greet { private String name; // standard constructors/getters } }
Обратите внимание, что Приветствуйте Тип сообщения определяется как статический внутренний класс внутри этого актера, который считается хорошей практикой. Принятые типы сообщений должны быть определены как можно ближе к актеру, чтобы избежать путаницы, на которых типы сообщений этот актер может обрабатывать.
Также обратите внимание на весенние аннотации @Component и @Scope – они определяют класс как весенний боб с прототип размах.
Область очень важна, потому что каждый запрос на поиск фасоли должен привести к недавно созданному экземпляру, так как это поведение соответствует жизненному циклу актера Акки. Если реализовать эту фасоль с некоторыми другими областями, типичный случай перезапуска субъектов в Akka, скорее всего, будет функционировать неправильно.
Наконец, обратите внимание, что мы не должны явно @Autowire Поздравительная служба пример – это возможно благодаря новой функции Весна 4.3 называется Неявная инъекция конструктора .
Осуществление GreeterService довольно просто, обратите внимание, что мы определили его как весной управляемых бобов, добавив @Component аннотация к нему (с однотонной области):
@Component public class GreetingService { public String greet(String name) { return "Hello, " + name; } }
4.2. Добавление весенней поддержки через расширение Akka
Самый простой способ интегрировать Spring с Akka – это расширение Akka.
Расширение – это однотонный экземпляр, созданный на одну актерную систему. Он состоит из самого класса расширения, который реализует интерфейс маркера Расширение , и расширение ID класса, который обычно наследует АннотацияЭкстензияИд .
Поскольку эти два класса тесно связаны между собой, имеет смысл реализовать Расширение класс, вложенный в РасширениеИд класс:
public class SpringExtension extends AbstractExtensionId{ public static final SpringExtension SPRING_EXTENSION_PROVIDER = new SpringExtension(); @Override public SpringExt createExtension(ExtendedActorSystem system) { return new SpringExt(); } public static class SpringExt implements Extension { private volatile ApplicationContext applicationContext; public void initialize(ApplicationContext applicationContext) { this.applicationContext = applicationContext; } public Props props(String actorBeanName) { return Props.create( SpringActorProducer.class, applicationContext, actorBeanName); } } }
Первые – ВеснаЭкстензия реализует единый создатьЭкстензия метод из АннотацияЭкстензияИд класс – что объясняет создание экземпляра расширения, СпрингЭкст объект.
ВеснаЭкстензия класс также имеет статическое поле SPRING_EXTENSION_PROVIDER который содержит ссылку на его единственный экземпляр. Часто имеет смысл добавить частного конструктора, чтобы прямо заявить, что ВеснаЭкстенция должен быть однотонный класс, но мы опустить его для ясности.
Во-вторых , статический внутренний класс СпрингЭкст является само расширение. Как Расширение это просто интерфейс маркера, мы можем определить содержание этого класса, как мы считаем нужным.
В нашем случае нам понадобится инициализировать метод хранения весеннего ПриложениеКонтекст пример – этот метод будет называться только один раз за инициализацию расширения.
Кроме того, мы будем требовать реквизит метод создания Реквизиты объект. Реквизиты например, это план для актера, и в нашем случае Props.create метод получает SpringActorProducer аргументы класса и конструктора для этого класса. Это аргументы, с помощью которые будет называться конструктором этого класса.
реквизит метод будет выполняться каждый раз, когда нам понадобится ссылка на актера, управляемого Весной.
Третий и последняя часть головоломки является SpringActorProducer класс. Он реализует КосвенныйАкторПродюсер интерфейс, который позволяет переопределить процесс мгновенного висяния для актера путем реализации производить и актерКласс методика.
Как вы, наверное, уже догадались, вместо прямого мгновенного, он всегда будет получать актер экземпляр из весны в ПриложениеКонтекст . Как мы сделали актера прототип -Scoped фасоли, каждый звонок в производить метод вернет новый экземпляр актера:
public class SpringActorProducer implements IndirectActorProducer { private ApplicationContext applicationContext; private String beanActorName; public SpringActorProducer(ApplicationContext applicationContext, String beanActorName) { this.applicationContext = applicationContext; this.beanActorName = beanActorName; } @Override public Actor produce() { return (Actor) applicationContext.getBean(beanActorName); } @Override public Class extends Actor> actorClass() { return (Class extends Actor>) applicationContext .getType(beanActorName); } }
4.3. Сложив все вместе
Единственное, что осталось сделать, это создать класс конфигурации Spring (отмеченный аннотацией @Configuration ), который скажет Spring сканировать текущий пакет вместе со всеми вложенными пакетами (это обеспечивается аннотацией @ComponentScan ) и создать контейнер Spring.
Нам нужно только добавить одну дополнительную фасоль – АктерСистема экземпляр – и инициализировать весеннее расширение на этом АктерСистема :
@Configuration @ComponentScan public class AppConfiguration { @Autowired private ApplicationContext applicationContext; @Bean public ActorSystem actorSystem() { ActorSystem system = ActorSystem.create("akka-spring-demo"); SPRING_EXTENSION_PROVIDER.get(system) .initialize(applicationContext); return system; } }
4.4. Извлечение весенних проводных актеров
Чтобы проверить, что все работает правильно, мы можем ввести АктерСистема например, в нашем коде (или какой-нибудь код приложения, управляемый весной, или тест на основе весны) создайте Реквизиты объект для актера, используя наше расширение, получить ссылку на актера через Реквизиты объект и попытаться поприветствовать кого-то:
ActorRef greeter = system.actorOf(SPRING_EXTENSION_PROVIDER.get(system) .props("greetingActor"), "greeter"); FiniteDuration duration = FiniteDuration.create(1, TimeUnit.SECONDS); Timeout timeout = Timeout.durationToTimeout(duration); Future
Здесь мы используем типичную akka.pattern.Patterns.ask шаблон, который возвращает Будущие пример. Как только вычисление завершено, Будущие решается с значением, которое мы вернули в нашем ПриветствиеАктор.onMessasge метод.
Мы можем либо дождаться результата, применив решение Scala Await.result метод к Будущие , или, что более предпочтительно, построить все приложение с асинхронными узорами.
5. Заключение
В этой статье мы показали, как интегрировать Spring Framework с Akka и autowire бобов в актеров.
Исходный код статьи доступен для на GitHub .