!147 feat #I64L3Q 增加 @ScriptMethod 注解

Merge pull request !147 from 与或非/issues/I64L3Q
This commit is contained in:
铂赛东
2022-12-12 05:07:28 +00:00
committed by Gitee
35 changed files with 848 additions and 6 deletions

View File

@@ -0,0 +1,25 @@
package com.yomahub.liteflow.script.annotation;
import com.yomahub.liteflow.annotation.AliasFor;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 用于标注在Script中可使用的java 方法
*
* @author tangkc
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface ScriptMethod {
@AliasFor("name")
String value() default "";
}

View File

@@ -0,0 +1,98 @@
package com.yomahub.liteflow.script.proxy;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.exception.LiteFlowException;
import com.yomahub.liteflow.exception.ScriptBeanMethodInvokeException;
import com.yomahub.liteflow.util.LiteFlowProxyUtil;
import com.yomahub.liteflow.util.SerialsUtil;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.implementation.InvocationHandlerAdapter;
import net.bytebuddy.matcher.ElementMatchers;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
/**
* 脚本方法代理
*/
public class ScriptMethodProxy {
/**
* 被代理的 bean
*/
private final Object bean;
/**
* 原始的类
*/
private final Class<?> orignalClass;
private final List<Method> scriptMethods;
public ScriptMethodProxy(Object bean, Class<?> orignalClass, List<Method> scriptMethods) {
this.bean = bean;
this.orignalClass = orignalClass;
this.scriptMethods = scriptMethods;
}
public Object getProxyScriptMethod() {
try {
return new ByteBuddy().subclass(orignalClass)
.name(buildClassName()) // 设置生成的类名
.method(ElementMatchers.any())
.intercept(InvocationHandlerAdapter.of(new AopInvocationHandler(bean, scriptMethods)))
.annotateType(orignalClass.getAnnotations())
.make()
.load(ScriptBeanProxy.class.getClassLoader())
.getLoaded()
.newInstance();
} catch (Exception e) {
throw new LiteFlowException(e);
}
}
private String buildClassName() {
return StrUtil.format("{}.ByteBuddy${}",
ClassUtil.getPackage(orignalClass),
SerialsUtil.generateShortUUID());
}
public static class AopInvocationHandler implements InvocationHandler {
private final Object bean;
private final Class<?> clazz;
private final Set<Method> methodSet;
public AopInvocationHandler(Object bean, List<Method> methods) {
this.bean = bean;
this.clazz = LiteFlowProxyUtil.getUserClass(bean.getClass());
this.methodSet = new HashSet<>(methods);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Optional<Method> invokeMethodOp = Arrays.stream(clazz.getMethods())
.filter(method::equals)
.findFirst();
if (!invokeMethodOp.isPresent()) {
String errorMsg = StrUtil.format("cannot find method[{}]", clazz.getName(), method.getName());
throw new ScriptBeanMethodInvokeException(errorMsg);
}
if (!methodSet.contains(method)) {
String errorMsg = StrUtil.format("script method[{}.{}] cannot be executed", clazz.getName(), method.getName());
throw new ScriptBeanMethodInvokeException(errorMsg);
}
return invokeMethodOp.get().invoke(bean, args);
}
}
}