Использование Spring для управления горячими загружаемыми объектами Groovy

Java Spring

причина

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

Сейчас надеюсь поставить некоторые работы по доступу к источникам данных и предобработке данных в скриптах Groovy доделать, и иметь такую ​​функцию: При стабильной работе проекта онлайн можно завершать запуск новых продуктов модификацией скриптов в БД.

решение

  • Plana: Java + горячая перезагрузка
  • PlanB: Groovy + горячая перезагрузка

В итоге было выбрано решение PlanB: позволить сценариям Groovy иметь доступ к источникам данных, вызывать службы rpc и т. д. Основная идея состоит в том, чтобы использовать Spring для управления сценариями Groovy.

  1. Сценарии Groovy сохраняются в базе данных. Запланированная задача постоянно обучает базу данных определять время обновления сценария Groovy.Если есть обновление, содержимое сценария считывается и анализируется как класс.
  2. Затем используйте инструментальный класс BeanDefinitionBuilder, предоставленный Spring, для создания BeanDefinition. BeanDefinition хранит метаданные сценариев Groovy, например зависимости от других классов.
  3. Затем поместите BeanDefinition в контекст Spring ApplicationContext и вызовите метод инициализации для выполнения внедрения зависимостей в компоненте.
  4. Наконец, вызовите context.getBean("xxx"), чтобы получить сценарий.

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

架构简图

Простая реализация

Hello.groovy Это скрипт Groovy, сохраненный в базе данных.

import org.springframework.beans.factory.annotation.Autowired

class Hello {
    @Autowired
    HelloService service;

    HelloService getService() {
        return service
    }

    def run() {
        print(service.hello())
    }
}

HelloService.java Это сервис, уже предоставленный в проекте, в реальном проекте это могут быть такие функции, как доступ к источникам данных.

import org.springframework.stereotype.Component;

@Component
public class HelloService {
    public String hello() {
        return "now hello";
    }
}

Первый шаг — получить контекст Spring ApplicationContext. Существует множество реализаций этого, например, наследование интерфейса ApplicationContextAware.

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

//从数据库中获取到脚本内容
String scriptContent = "......";
//编译
Class clazz = new GroovyClassLoader().parseClass(scriptContent);

Третий шаг — поместить bean-компонент в контекст и выполнить внедрение зависимостей.

BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
BeanDefinition beanDefinition = beanDefinitionBuilder.getRawBeanDefinition();
context.getAutowireCapableBeanFactory().applyBeanPostProcessorsAfterInitialization(beanDefinition, "hello");
beanFactory.registerBeanDefinition("hello", beanDefinition);

Четвертый шаг, получение скрипта Groovy из контекста

Hello hello = context.getBean("hello");
hello.run();
//console中应当输出下面内容,此时说明HelloService已经成功注入到groovy脚本中了
//now hello

использованная литература

  1. Groovy делает Spring лучше. Часть 2. Изменение поведения приложения во время выполнения. Добавление динамически обновляемых компонентов в приложение Spring с помощью Groovy.
  2. Динамически вводить bean-компоненты в контейнер Spring
  3. Весенняя динамическая регистрация bean Wang Yan
  4. Spring Dynamic Registration Bean Li Jiaming