причина
Последние проекты относятся к типу анализа данных, и функция анализа данных требуется для быстрого запуска. В настоящее время в этом проекте используется язык Java + Groovy. Причина использования Groovy проста, поскольку сценарии Groovy поддерживают горячую перезагрузку. В проекте простая работа по анализу данных, такая как некоторая статистика, сортировка, фильтрация и т. д., выполняется в Groovy. Когда необходимо запустить новую функцию анализа данных, необходимо только написать новый скрипт и загрузить его в JVM.
Сейчас надеюсь поставить некоторые работы по доступу к источникам данных и предобработке данных в скриптах Groovy доделать, и иметь такую функцию: При стабильной работе проекта онлайн можно завершать запуск новых продуктов модификацией скриптов в БД.
решение
- Plana: Java + горячая перезагрузка
- PlanB: Groovy + горячая перезагрузка
В итоге было выбрано решение PlanB: позволить сценариям Groovy иметь доступ к источникам данных, вызывать службы rpc и т. д. Основная идея состоит в том, чтобы использовать Spring для управления сценариями Groovy.
- Сценарии Groovy сохраняются в базе данных. Запланированная задача постоянно обучает базу данных определять время обновления сценария Groovy.Если есть обновление, содержимое сценария считывается и анализируется как класс.
- Затем используйте инструментальный класс BeanDefinitionBuilder, предоставленный Spring, для создания BeanDefinition. BeanDefinition хранит метаданные сценариев Groovy, например зависимости от других классов.
- Затем поместите BeanDefinition в контекст Spring ApplicationContext и вызовите метод инициализации для выполнения внедрения зависимостей в компоненте.
- Наконец, вызовите 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
использованная литература
- Groovy делает Spring лучше. Часть 2. Изменение поведения приложения во время выполнения. Добавление динамически обновляемых компонентов в приложение Spring с помощью Groovy.
- Динамически вводить bean-компоненты в контейнер Spring
- Весенняя динамическая регистрация bean Wang Yan
- Spring Dynamic Registration Bean Li Jiaming