场景:

    1. 实时计算任务中,采用groovy脚本定义计算逻辑。在执行时动态加载并执行
    2. 自定义告警插件:业务对于告警文案的展现、告警消息的处理有自定义的诉求,提供一套让业务可基于告警上下文自定义告警处理逻辑的能力,比如决定是否要拦截,告警文案的自定义等

    方案:

    1、后台界面提供 groovy脚本编写和管理能力

    2、GroovyRepository

    1. <dependency>
    2. <groupId>org.codehaus.groovy</groupId>
    3. <artifactId>org.codehaus.groovy.all</artifactId>
    4. <version>1.8.9.cloudengine4</version>
    5. </dependency>
    1. import groovy.lang.GroovyClassLoader;
    2. import groovy.lang.GroovyObject;
    3. public class GroovyRepository {
    4. private static final Logger logger = LoggerFactory.getLogger(GroovyRepository.class);
    5. private static final Map<String/*实际脚本内容*/, GroovyObject> cache = new HashMap<>(50);
    6. private static final GroovyClassLoader loader = new GroovyClassLoader();
    7. public static synchronized GroovyObject get(String code) {
    8. //因为这里本身是static的方法,所以需要通过spring上下文 来 获取 service,并执行
    9. InterceptorScriptService interceptorScriptService = SmartBeanContainer.getBean("interceptorScriptService", InterceptorScriptServiceImpl.class);
    10. String script = interceptorScriptService.getInterceptorScriptByCode(code);
    11. // TODO remove,为了方便测试,将脚本维护在了后台参数一份。因为后台的脚本维护页面还没做
    12. RuntimeArgCacheService runtimeArgCacheService = SmartBeanContainer.getBean("runtimeArgCacheService", RuntimeArgCacheServiceImpl.class);
    13. String scriptBackup = runtimeArgCacheService.queryRuntimeArgs(RunTimeArgConstant.TYPE_INTERCEPTOR_INFO, code);
    14. if(StringUtils.isNotBlank(scriptBackup)) {
    15. script = scriptBackup;
    16. }
    17. //------------------------------------------------------------------------------------
    18. GroovyObject object = cache.get(script);
    19. if (object == null) {
    20. Class<?> clazz = loader.parseClass(script);
    21. try {
    22. object = (GroovyObject) clazz.newInstance();
    23. } catch (InstantiationException e) {
    24. logger.error("", e);
    25. } catch (IllegalAccessException e) {
    26. logger.error("", e);
    27. }
    28. if (object != null) {
    29. cache.put(script, object);
    30. }
    31. }
    32. return object;
    33. }
    34. }

    3、脚本的执行

    1. //这里可以强转成自己的业务对象
    2. interceptor = (SmartInterceptor) GroovyRepository.get(alarmInterceptor.getCode());
    3. // 依赖注入:groovy脚本里是可能用spring中的各种service的,通过这里来给他注入进去,因为grrovy对象本身不受spring管理,
    4. // 所以需要手动注入
    5. SmartBeanContainer.getApplicationContext().getAutowireCapableBeanFactory().autowireBean(interceptor);
    6. // 极端方法:可以在这里再初始化进去spring当前的上下文,
    7. // 这样在interceptor的实现里 也可以通过applicationContext来获取bean了
    8. interceptor.initApplicationContext(SmartBeanContainer.getApplicationContext());