我是靠谱客的博主 真实烤鸡,这篇文章主要介绍springboot集成groovy执行代码一.springboot中执行groovy文件二,通过数据库保存groovy内容,动态执行groovy脚本,现在分享给大家,希望可以做个参考。

springboot集成groovy动态执行代码

springboot版本号:2.2.2.RELEASE

在pom.xml中集成groovy

复制代码
1
2
3
4
5
6
<dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-all</artifactId> <version>1.8.9</version> <scope>compile</scope> </dependency>

一.springboot中执行groovy文件

main文件直接调用groovy文件,有三种方式

方式一生成Test.groovy:

复制代码
1
2
3
4
5
6
7
8
9
package com.example.demo.groovy public class Test { public static String test(String id) { return "younger--->" + id; } }

方式二生成test1.groovy

复制代码
1
2
3
4
5
6
package com.example.demo.groovy.groovyscript def test(id){ return "test2 id:"+ id; }

方法三生成test2.groovy

复制代码
1
2
3
4
package com.example.demo.groovy.groovyscript output = "test3 id: ${id}, name: ${name}"

通过Java的main方法调用groovy文件,得到执行结束

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.example.demo; import com.example.demo.controller.CalculateController; import groovy.lang.Binding; import groovy.lang.GroovyClassLoader; import groovy.lang.GroovyObject; import groovy.lang.Script; import groovy.util.GroovyScriptEngine; import groovy.util.ResourceException; import groovy.util.ScriptException; import java.io.File; import java.io.IOException; /** * @program: demo * @description: 本地main方法执行groovy文件 * @author: younger * @create: 2021-05-07 15:42 **/ public class GroovyTest { public static void main(String[] args) throws IOException, IllegalAccessException, InstantiationException, ResourceException, ScriptException { //方式一调用groovy文件 ClassLoader parent = CalculateController.class.getClassLoader(); GroovyClassLoader loader = new GroovyClassLoader(parent); Class groovyClass = loader.parseClass(new File("src/main/java/com/example/demo/groovy/Test.groovy")); //得到groovy对象 GroovyObject groovyObject= (GroovyObject)groovyClass.newInstance(); //执行对象的test方法,并传参数-"id---1" String result = (String) groovyObject.invokeMethod("test", "id---1"); System.out.println("result--------->" + result); //方式二调用groovy文件,找到groovy脚本所在文件夹 GroovyScriptEngine engine = new GroovyScriptEngine("src/main/java/com/example/demo/groovy/groovyscript"); //得到Script对象 Script script = engine.createScript("test1.groovy", new Binding()); //执行Script对象的test方法,并传参数-"id---1" result = (String) script.invokeMethod("test", "id----2"); System.out.println("result--------->" + result); //方式三调用groovy文件 // GroovyScriptEngine engine = new GroovyScriptEngine("src/main/java/com/example/demo/groovy/groovyscript"); Binding binding = new Binding(); //封装参数 binding.setVariable("id","id---3"); binding.setVariable("name", "younger"); //执行test2.groovy脚本 engine.run("test2.groovy", binding); //返回output result = binding.getVariable("output").toString(); System.out.println("result--------->" + result); } }

二,通过数据库保存groovy内容,动态执行groovy脚本

数据库mysql,创建groovy规则表:calculate_rule

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
CREATE TABLE `calculate_rule` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `interface_id` varchar(128) NOT NULL COMMENT '接口id', `bean_name` varchar(64) NOT NULL COMMENT 'bean_name', `calculate_rule` text NOT NULL COMMENT 'groovy脚本内容', `calculate_type` varchar(64) NOT NULL COMMENT '状态', `status` varchar(16) NOT NULL DEFAULT 'ENABLE' COMMENT 'ENABLE-启用/DISENABLE-停用', `extend_info` varchar(4096) DEFAULT NULL, `created_time` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), `modified_time` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COMMENT='calculate rule'; insert into `calculate_rule` (`id`, `interface_id`, `bean_name`, `calculate_rule`, `calculate_type`, `status`, `extend_info`, `created_time`, `modified_time`) values('1','B.integration.A.calculate.reward','rewardCalculateParser','package com.example.demo.groovy.calculate.impl;nimport com.example.demo.entity.request.CalculateRequest;nimport com.example.demo.entity.response.CalculateResponse;nimport com.example.demo.groovy.calculate.CalculateParsernimport com.example.demo.service.CalculateInterestRuleService;nimport org.apache.commons.lang3.StringUtilsnimport org.springframework.beans.factory.annotation.Autowirednimport org.springframework.stereotype.Service;nimport java.math.RoundingMode;n/**n * 计算推广奖金n */npublic class RewardCalculateParser implements CalculateParser {n @Autowiredn private CalculateInterestRuleService calculateInterestRuleService;n @Overriden public CalculateResponse parse(CalculateRequest request) {n String result = calculateInterestRuleService.test("younger");n System.out.println("calculateInterestRuleService.test-------->" + result);n Map<String, Object> extendInfo = request.getExtendInfo();n String interfaceId = request.getInterfaceId();n BigDecimal totalAmount = BigDecimal.ZERO;n if (StringUtils.isNotBlank((String) extendInfo.get("totalAmount"))) {n totalAmount = new BigDecimal((String) extendInfo.get("totalAmount"));n }n int refererNumber = 0;n if (StringUtils.isNotBlank((String) extendInfo.get("refererNumber"))) {n refererNumber = Integer.parseInt((String) extendInfo.get("refererNumber"));n }n System.out.println("进入奖金计算逻辑,总金额为:" + totalAmount + ",邀请人数为:" + refererNumber);n n BigDecimal reward = totalAmount.multiply(new BigDecimal(String.valueOf(refererNumber)))n .divide(new BigDecimal("100")).divide(new BigDecimal("365"),4, RoundingMode.HALF_DOWN);n CalculateResponse response = new CalculateResponse();n response.setInterfaceId(interfaceId);n Map<String, Object> map = new HashMap<>();n map.put("reward", reward);n response.setExtendInfo(map);n System.out.println("退出奖金计算逻辑,总奖金为:" + reward);n return response;n }n}n','reward','ENABLE',NULL,'2020-07-06 09:27:58.279144','2021-05-07 17:17:19.771010'); insert into `calculate_rule` (`id`, `interface_id`, `bean_name`, `calculate_rule`, `calculate_type`, `status`, `extend_info`, `created_time`, `modified_time`) values('2','B.integration.A.calculate.sum','sumCalculateParser','package com.example.demo.groovy.calculate.impl;nnimport com.example.demo.entity.request.CalculateRequest;nimport com.example.demo.entity.response.CalculateResponse;nimport com.example.demo.groovy.calculate.CalculateParser;nimport org.apache.commons.lang3.StringUtils;nnimport java.math.BigDecimal;nimport java.math.RoundingMode;nimport java.util.HashMap;nimport java.util.Map;nn/**n * 计算推广奖金n */npublic class SumCalculateParser implements CalculateParser {nn @Overriden public CalculateResponse parse(CalculateRequest request) {nn Map<String, Object> extendInfo = request.getExtendInfo();nn String interfaceId = request.getInterfaceId();nn BigDecimal totalAmount = BigDecimal.ZERO;n if (StringUtils.isNotBlank((String) extendInfo.get("totalAmount"))) {n totalAmount = new BigDecimal((String) extendInfo.get("totalAmount"));n }nn int refererNumber = 0;n if (StringUtils.isNotBlank((String) extendInfo.get("refererNumber"))) {n refererNumber = Integer.parseInt((String) extendInfo.get("refererNumber"));n }nnn System.out.println("进入奖金计算逻辑,总金额为:" + totalAmount + ",邀请人数为:" + refererNumber);n n BigDecimal sum = totalAmount.multiply(new BigDecimal(refererNumber));n CalculateResponse response = new CalculateResponse();nn response.setInterfaceId(interfaceId);n Map<String, Object> map = new HashMap<>();n map.put("sum", sum);nn response.setExtendInfo(map);nn System.out.println("退出奖金计算逻辑,总奖金为:" + sum);n return response;n }n}','reward','ENABLE',NULL,'2020-07-06 09:27:58.279144','2020-07-06 13:23:51.311882');

原理:把groovy脚本放在表calculate_rule中的calculate_rule,spring-boot启动加载calculate_rule中启用的数据,动态成生spring.xml文件把groovy脚本加载至spring容器中。

1.创建GroovyDynamicConfiguration类,在spring-boot启动时加载groovy脚本至spring容器中:

注:请看重点方法

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
package com.example.demo.groovy.core; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.example.demo.entity.CalculateRuleDO; import com.example.demo.groovy.cache.BeanName; import com.example.demo.groovy.cache.BeanNameCache; import com.example.demo.groovy.cache.GroovyInfo; import com.example.demo.groovy.cache.GroovyInnerCache; import com.example.demo.service.CalculateInterestRuleService; import groovy.lang.GroovyClassLoader; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeansException; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.ResourceEntityResolver; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Configuration; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import javax.annotation.Resource; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; /** * @program: demo * @description: 动态加载groovy脚本至spring容器中 * @author: younger * @create: 2021-05-07 15:42 **/ @Configuration public class GroovyDynamicConfiguration implements ApplicationContextAware, InitializingBean { private ConfigurableApplicationContext applicationContext; private static final GroovyClassLoader groovyClassLoader = new GroovyClassLoader(GroovyDynamicConfiguration.class.getClassLoader()); @Resource private CalculateInterestRuleService calculateInterestRuleService; @Override public void afterPropertiesSet() throws Exception { long start = System.currentTimeMillis(); System.out.println("开始从数据库解析groovy脚本..."); init(); long cost = System.currentTimeMillis() - start; System.out.println("结束从数据库解析groovy脚本...,耗时:" + cost); } /** * 启动spring-boot就加载数据库中groovy脚本至spring容器管理 */ private void init() { //从mysql中获取groovy脚本规则 List<CalculateRuleDO> calculateRuleDOS = calculateInterestRuleService.list(new QueryWrapper<CalculateRuleDO>().eq("status", "ENABLE")); List<BeanName> beanNameList = new ArrayList<>(); List<GroovyInfo> groovyInfos = convert(calculateRuleDOS, beanNameList); init(groovyInfos, beanNameList); } /** * 重点方法 */ private void init(List<GroovyInfo> groovyInfos, List<BeanName> beanNameList) { if (CollectionUtils.isEmpty(groovyInfos)) { return; } ConfigurationXMLWriter config = new ConfigurationXMLWriter(); //生成配置文件内容 addConfiguration(config, groovyInfos); //把groovy规则加载至内存 put2map(groovyInfos, beanNameList); //加载至spring容器中 loadBeanDefinitions(config); } /** * 重新从mysql加载groovy脚本 */ public void refresh() { List<CalculateRuleDO> calculateRuleDOS = calculateInterestRuleService.list(new QueryWrapper<CalculateRuleDO>().eq("status", "ENABLE")); List<BeanName> beanNameList = new ArrayList<>(); List<GroovyInfo> groovyInfos = convert(calculateRuleDOS, beanNameList); if (CollectionUtils.isEmpty(groovyInfos)) { return; } // loadBeanDefinitions 之后才会生效 destroyBeanDefinition(groovyInfos); destroyScriptBeanFactory(); ConfigurationXMLWriter config = new ConfigurationXMLWriter(); addConfiguration(config, groovyInfos); put2map(groovyInfos, beanNameList); loadBeanDefinitions(config); } private List<GroovyInfo> convert(List<CalculateRuleDO> calculateRuleDOS, List<BeanName> beanNameList) { List<GroovyInfo> groovyInfos = new LinkedList<>(); if (CollectionUtils.isEmpty(calculateRuleDOS)) { return groovyInfos; } for (CalculateRuleDO calculateRuleDO : calculateRuleDOS) { GroovyInfo groovyInfo = new GroovyInfo(); groovyInfo.setClassName(calculateRuleDO.getBeanName()); groovyInfo.setGroovyContent(calculateRuleDO.getCalculateRule()); groovyInfos.add(groovyInfo); BeanName beanName = new BeanName(); beanName.setInterfaceId(calculateRuleDO.getInterfaceId()); beanName.setBeanName(calculateRuleDO.getBeanName()); beanNameList.add(beanName); } return groovyInfos; } private void addConfiguration(ConfigurationXMLWriter config, List<GroovyInfo> groovyInfos) { for (GroovyInfo groovyInfo : groovyInfos) { writeBean(config, groovyInfo); } } private void loadBeanDefinitions(ConfigurationXMLWriter config) { /** * contextString= * <?xml version="1.0" encoding="UTF-8" standalone="no"?> * <beans xmlns="http://www.springframework.org/schema/beans" * xmlns:lang="http://www.springframework.org/schema/lang" * xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" * default-autowire="byName" * xsi:schemaLocation="http://www.springframework.org/schema/beans * http://www.springframework.org/schema/beans/spring-beans-2.5.xsd * http://www.springframework.org/schema/lang * http://www.springframework.org/schema/lang/spring-lang-2.5.xsd"> * <lang:groovy id="rewardCalculateParser" script-source="database:rewardCalculateParser"/> * <lang:groovy id="sumCalculateParser" script-source="database:sumCalculateParser"/> * </beans> * 生成加载至spring容器的xml,为了把groovy对应的对象交给spring容器来管理。 */ String contextString = config.getContent(); if(StringUtils.isBlank(contextString)) { return ; } XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader((BeanDefinitionRegistry) this.applicationContext.getBeanFactory()); beanDefinitionReader.setResourceLoader(this.applicationContext); beanDefinitionReader.setBeanClassLoader(applicationContext.getClassLoader()); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this.applicationContext)); beanDefinitionReader.loadBeanDefinitions(new InMemoryResource(contextString)); String[] postProcessorNames = applicationContext.getBeanFactory().getBeanNamesForType(CustomScriptFactoryPostProcessor.class, true, false); for (String postProcessorName : postProcessorNames) { applicationContext.getBeanFactory().addBeanPostProcessor((BeanPostProcessor) applicationContext.getBean(postProcessorName)); } } private void destroyBeanDefinition(List<GroovyInfo> groovyInfos) { DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory(); for (GroovyInfo groovyInfo : groovyInfos) { try { beanFactory.removeBeanDefinition(groovyInfo.getClassName()); } catch (Exception e) { System.out.println("【Groovy】delete groovy bean definition exception. skip:" + groovyInfo.getClassName()); } } } private void destroyScriptBeanFactory() { String[] postProcessorNames = applicationContext.getBeanFactory().getBeanNamesForType(CustomScriptFactoryPostProcessor.class, true, false); for (String postProcessorName : postProcessorNames) { CustomScriptFactoryPostProcessor processor = (CustomScriptFactoryPostProcessor) applicationContext.getBean(postProcessorName); processor.destroy(); } } private void writeBean(ConfigurationXMLWriter config, GroovyInfo groovyInfo) { if (checkSyntax(groovyInfo)) { DynamicBean bean = composeDynamicBean(groovyInfo); config.write(GroovyConstant.SPRING_TAG, bean); } } private boolean checkSyntax(GroovyInfo groovyInfo) { try { groovyClassLoader.parseClass(groovyInfo.getGroovyContent()); } catch (Exception e) { return false; } return true; } private DynamicBean composeDynamicBean(GroovyInfo groovyInfo) { DynamicBean bean = new DynamicBean(); String scriptName = groovyInfo.getClassName(); Assert.notNull(scriptName, "parser className cannot be empty!"); //设置bean的属性,这里只有id和script-source。 bean.put("id", scriptName); bean.put("script-source", GroovyConstant.SCRIPT_SOURCE_PREFIX + scriptName); return bean; } private void put2map(List<GroovyInfo> groovyInfos, List<BeanName> beanNameList) { GroovyInnerCache.put2map(groovyInfos); BeanNameCache.put2map(beanNameList); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = (ConfigurableApplicationContext) applicationContext; } }

2.调用Controller测试groovy动态脚本

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package com.example.demo.controller; import java.util.Map; import java.util.HashMap; import javax.annotation.Resource; import com.example.demo.entity.request.CalculateRequest; import com.example.demo.entity.response.CalculateResponse; import com.example.demo.groovy.calculate.CalculateParser; import com.example.demo.groovy.calculate.GroovyParserEngine; import com.example.demo.groovy.core.GroovyDynamicConfiguration; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class CalculateController { @Resource private GroovyParserEngine groovyParserEngine; @Resource private GroovyDynamicConfiguration groovyDynamicLoader; @Resource private CalculateParser rewardCalculateParserGroovy; @RequestMapping("/calculate") public Map<String, Object> calculate() { String interfaceId = "B.integration.A.calculate.reward"; Map<String, Object> map = new HashMap<>(); map.put("totalAmount", "10"); map.put("refererNumber", "5"); CalculateRequest request = new CalculateRequest(); request.setInterfaceId(interfaceId); request.setExtendInfo(map); CalculateResponse response = groovyParserEngine.parse(request); return response.getExtendInfo(); } @RequestMapping("/refresh") public void refresh() { groovyDynamicLoader.refresh(); } }
复制代码
1
2
3
4
5
6
7
8
9
10
package com.example.demo.groovy.calculate; import com.example.demo.entity.request.CalculateRequest; import com.example.demo.entity.response.CalculateResponse; public interface GroovyParserEngine { CalculateResponse parse(CalculateRequest request); }
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.example.demo.groovy.calculate.impl; import com.example.demo.groovy.cache.BeanNameCache; import com.example.demo.groovy.calculate.CalculateParser; import com.example.demo.groovy.calculate.GroovyParserEngine; import com.example.demo.entity.request.CalculateRequest; import com.example.demo.entity.response.CalculateResponse; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Service; @Service public class GroovyParserEngineImpl implements GroovyParserEngine, ApplicationContextAware { private ApplicationContext applicationContext; @Override public CalculateResponse parse(CalculateRequest request) { String beanName = BeanNameCache.getByInterfaceId(request.getInterfaceId()); CalculateParser parser = (CalculateParser) applicationContext.getBean(beanName); return parser.parse(request); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } }

启动项目,调用http://localhost:8888/calculate,测试结果。
代码下载地址:https://download.csdn.net/download/yangxiang_Younger/18445827

最后

以上就是真实烤鸡最近收集整理的关于springboot集成groovy执行代码一.springboot中执行groovy文件二,通过数据库保存groovy内容,动态执行groovy脚本的全部内容,更多相关springboot集成groovy执行代码一内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(58)

评论列表共有 0 条评论

立即
投稿
返回
顶部