Groovy模板引擎 API 构建动态脚本

本文介绍了如何使用Groovy模板引擎在Java项目中创建动态脚本,以及如何将Groovy脚本对象注册为SpringIoC容器中的Bean,以便进行规则编排和数据处理。
摘要由CSDN通过智能技术生成

目录


Groovy模板引擎 API 构建动态脚本

可以利用Groovy提供的模板引擎, 在代码中编写脚本, 来完成一些动态化的需求, 案例如下, 当字符串长度等于4时, 执行打印

public class RuleEngine {

    private static final ConcurrentHashMap<String, Template> SCRIPT_CACHE = new ConcurrentHashMap<>();

    private static final SimpleTemplateEngine ENGINE = new SimpleTemplateEngine();

    private static final String CONDITION_STR_TEMPLATE = "${%s ? true : false}";

    private static final String EXECUTE_STR_TEMPLATE = "${%s}";

    public static void main(String[] args) {
        String request = "data";
        String condition = "request.length() == 4";
        String execute = "System.out.println(request)";

        if (condition(condition, request)) {
            execute(execute, request);
        }
    }

    public static boolean condition(String condition, String request) {
        boolean result;
        String conditionTemplate = String.format(CONDITION_STR_TEMPLATE, condition);
        Map<String, Object> context = new HashMap<>();
        context.put("request", request);
        try {
            Template template;
            if (SCRIPT_CACHE.containsKey(condition)) {
                template = SCRIPT_CACHE.get(condition);
            } else {
                template = ENGINE.createTemplate(conditionTemplate);
                SCRIPT_CACHE.put(condition, template);
            }
            Writer writer = new StringWriter();
            template.make(context).writeTo(writer);
            result = Boolean.parseBoolean(writer.toString());
        } catch (Exception e) {
            throw new RuntimeException("模板解析异常" + conditionTemplate);
        }
        return result;
    }

    public static void execute(String execute, String request) {
        String executeTemplate = String.format(EXECUTE_STR_TEMPLATE, execute);
        Map<String, Object> context = new HashMap<>();
        context.put("request", request);
        Template template;
        try {
            if (SCRIPT_CACHE.containsKey(execute)) {
                template = SCRIPT_CACHE.get(execute);
            } else {
                template = ENGINE.createTemplate(executeTemplate);
                SCRIPT_CACHE.put(execute, template);
            }
            template.make(context).writeTo(new StringWriter());
        } catch (Exception e) {
            throw new RuntimeException("模板解析异常" + executeTemplate);
        }
    }

}

Groovy动态对象注册为Spring IOC中的Bean

groovy script脚本

内容如下, 与Java语法完全兼容

package groovy;

import com.github.service.GroovyBeanCommand
import org.slf4j.Logger
import org.slf4j.LoggerFactory

import java.lang.invoke.MethodHandles;

public class FoobarCommand implements GroovyBeanCommand {

    private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

    @Override
    String run() {
        LOGGER.info("foobar command");
        return "FoobarCommand Data";
    }

}

约定的脚本所需实现的接口

 

public interface GroovyBeanCommand { String run(); }

外部传入script的入口

@PostMapping("/command/add")
public void addGroovyCommand(@RequestParam String groovyBeanName, @RequestParam String script) {
    GroovyContextUtils.autowireBean(groovyBeanName, script);
}

@GetMapping("/command/run")
public Object runGroovyCommand(@RequestParam String groovyBeanName) {
    GroovyBeanCommand command = GroovyContextUtils.getBean(groovyBeanName, GroovyBeanCommand.class);
    return command.run();
}

将script注入到IOC中的工具类

@Component
public class GroovyContextUtils implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    private static final GroovyClassLoader CLASS_LOADER = new GroovyClassLoader();

    @Override
    public void setApplicationContext(@NonNull ApplicationContext context) {
        applicationContext = context;
    }

    public static void autowireBean(String beanName, String script) {
        Class<?> clazz = CLASS_LOADER.parseClass(script);
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
        BeanDefinition beanDefinition = beanDefinitionBuilder.getRawBeanDefinition();
        beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);

        AutowireCapableBeanFactory autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory();
        autowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(beanDefinition, beanName);

        BeanDefinitionRegistry beanRegistry = (BeanDefinitionRegistry) autowireCapableBeanFactory;
        if (beanRegistry.containsBeanDefinition(beanName)) {
            beanRegistry.removeBeanDefinition(beanName);
        }
        beanRegistry.registerBeanDefinition(beanName, beanDefinition);
    }

    public static <T> T getBean(String beanName, Class<T> clazz) {
        return applicationContext.getBean(beanName, clazz);
    }

    public static <T> T getBean(Class<T> clazz) {
        return applicationContext.getBean(clazz);
    }

}

动态脚本与规则编排

自定义一套规则组, 将脚本编号保存, 按照所需要顺序组合起来, 实现规则的编排和可插拔, 并按照流程处理数据流

伪代码如下

public void process(Data data) {
    List<Handler> handlers = getHandlers(data.getBizCode());
    for(Handler handler : handlers) {
        handler.run(data);
    }
}

__EOF__

本文作者:梅子酒 
本文链接:https://www.cnblogs.com/plumswine/p/14238816.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值