在工作流中各个模板引擎都需要要执行一个动态业务,这些动态业务有多种实现方式,最常用的就是用户自己写一段脚本文件,然后工作流引擎执行到这里的时候,运行这个脚本文件。
1、添加groovy依赖pom.xml
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy</artifactId>
<version>2.5.1</version>
</dependency>
2、Spring上线问工具类
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class SpringContextUtils implements ApplicationContextAware {
static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext context)
throws BeansException {
SpringContextUtils.context = context;
}
public static ApplicationContext getContext() {
return context;
}
public static void autowireBean(Object bean) {
context.getAutowireCapableBeanFactory().autowireBean(bean);
}
public static <T> T getBean(Class<T> clazz) {
return context.getBean(clazz);
}
}
3、写个控制器运行groovy脚本
import com.ruizton.util.SpringContextUtils;
import groovy.lang.GroovyClassLoader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.lang.reflect.Method;
@RestController
public class GroovyController {
@RequestMapping("/runScript")
public Object runScript(String script) throws Exception {
if (script != null) {
// 这里其实就是groovy的api动态的加载生成一个Class,然后反射生成对象,然后执行run方法,最后返回结果
// 最精华的地方就是SpringContextUtils.autowireBean,可以实现自动注入bean,
Class clazz = new GroovyClassLoader().parseClass(script);
Method run = clazz.getMethod("run");
Object o = clazz.newInstance();
SpringContextUtils.autowireBean(o);
Object ret = run.invoke(o);
return ret;
} else {
return "no script";
}
}
}
4、在线写groovy脚本调用3中接口并返回运行结果Foo.groovy
import org.springframework.beans.factory.annotation.Autowired
class Foo {
@Autowired
UserService userService;
Object run() {
// do something
def user = userService.findById(666);
if (user != null) {
return user .name
}
return null
}
}
不写类直接写代码块也是可以的
test.groovy
def sum = 1 * 2 * 3
return "result= " + sum
上面代码也会生成一个Class对象,里面的代码默认在run方法下面,所以控制器哪里都是调用的run方法.
动态注册Bean,Controller到Spring容器
结合上面的SpringContextUtil使用
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import java.lang.reflect.Method;
/**
* 动态注册对象到容器
*/
@Slf4j
public class DynamicLoadUtils {
/**
* 动态添加controller到spring容器
* @param controllerBeanName
* @throws Exception
*/
public static void registerController(String controllerBeanName) throws Exception {
final RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping)
SpringContextUtil.applicationContext.getBean("requestMappingHandlerMapping");
if (requestMappingHandlerMapping != null) {
String handler = controllerBeanName;
Object controller = SpringContextUtil.applicationContext.getBean(handler);
if (controller == null) {
return;
}
unregisterController(controllerBeanName);
//注册Controller
Method method = requestMappingHandlerMapping.getClass().getSuperclass().getSuperclass().
getDeclaredMethod("detectHandlerMethods", Object.class);
method.setAccessible(true);
method.invoke(requestMappingHandlerMapping, handler);
log.info("==>动态注入controller:{}",controllerBeanName);
}
}
/**
* 动态删除controller
* @param controllerBeanName
*/
public static void unregisterController(String controllerBeanName) {
final RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping)
SpringContextUtil.applicationContext.getBean("requestMappingHandlerMapping");
if (requestMappingHandlerMapping != null) {
String handler = controllerBeanName;
Object controller = SpringContextUtil.applicationContext.getBean(handler);
if (controller == null) {
return;
}
final Class<?> targetClass = controller.getClass();
ReflectionUtils.doWithMethods(targetClass, new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) {
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
try {
Method createMappingMethod = RequestMappingHandlerMapping.class.
getDeclaredMethod("getMappingForMethod", Method.class, Class.class);
createMappingMethod.setAccessible(true);
RequestMappingInfo requestMappingInfo = (RequestMappingInfo)
createMappingMethod.invoke(requestMappingHandlerMapping, specificMethod, targetClass);
if (requestMappingInfo != null) {
requestMappingHandlerMapping.unregisterMapping(requestMappingInfo);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}, ReflectionUtils.USER_DECLARED_METHODS);
}
}
/**
* 向spring容器中添加bean
* @param className
* @param serviceName
* @param app
*/
public static void addBean(String className, String serviceName, ApplicationContext app) {
try {
Class<?> clazz = Thread.currentThread().getContextClassLoader().loadClass(className);
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
registerBean(serviceName, beanDefinitionBuilder.getRawBeanDefinition(), app);
} catch (ClassNotFoundException e) {
System.out.println(className + ",主动注册失败.");
}
}
/**
* 向spring容器中添加bean
* @param clazz
* @param serviceName
* @param app
*/
public static void addBean(Class clazz, String serviceName, ApplicationContext app) {
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
registerBean(serviceName, beanDefinitionBuilder.getRawBeanDefinition(), app);
}
/**
* 向spring容器注册bean核心代码
* @param beanName
* @param beanDefinition
* @param context
*/
private static void registerBean(String beanName, BeanDefinition beanDefinition, ApplicationContext context) {
ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) context;
BeanDefinitionRegistry beanDefinitonRegistry = (BeanDefinitionRegistry) configurableApplicationContext
.getBeanFactory();
beanDefinitonRegistry.registerBeanDefinition(beanName, beanDefinition);
log.info("==> 动态注册bean:{}",beanName);
}
}
参考文档:
https://yq.aliyun.com/articles/665345
https://blog.csdn.net/qq_38206090/article/details/103101323?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-13.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-13.nonecase
网友评论