mirror of
https://github.com/slhaf/Partner.git
synced 2026-05-12 16:53:04 +08:00
推进框架中的模块注册机制。引入 ByteBuddy 完成针对模块的代理实现。
- 调整部分包结构 - 重构 AgentRegisterContext ,将不同的 Context 内容按照对应模块进行封装 - 调整了‘添加可扫描包’的添加逻辑、新增了添加外部目录的扫描逻辑 - 新增几个异常类 - 在 ModuleCheckFactory 中新增了对于执行模块‘是否实现无参构造方法’的校验逻辑 - 引入 ByteBuddy 库负责构造执行模块实例,并添加对应的hook逻辑 - 调整 ModuleRegisterFactory 的逻辑,允许注册加载Module内的Hook方法 - 调整依赖引用关系,因为Partner-Main、Partner-Demo都继承自Partner-Api包,故将通用依赖移动至Api的pom文件中
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package work.slhaf.partner.api.factory.entity;
|
||||
package work.slhaf.partner.api.factory;
|
||||
|
||||
import work.slhaf.partner.api.factory.capability.exception.CapabilityFactoryExecuteFailedException;
|
||||
import work.slhaf.partner.api.factory.context.AgentRegisterContext;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
@@ -1,32 +1,35 @@
|
||||
package work.slhaf.partner.api.factory;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import org.reflections.util.ClasspathHelper;
|
||||
import work.slhaf.partner.api.entity.AgentContext;
|
||||
import work.slhaf.partner.api.factory.capability.CapabilityCheckFactory;
|
||||
import work.slhaf.partner.api.factory.capability.CapabilityInjectFactory;
|
||||
import work.slhaf.partner.api.factory.capability.CapabilityRegisterFactory;
|
||||
import work.slhaf.partner.api.factory.config.ConfigLoaderFactory;
|
||||
import work.slhaf.partner.api.factory.entity.AgentRegisterContext;
|
||||
import work.slhaf.partner.api.factory.context.AgentRegisterContext;
|
||||
import work.slhaf.partner.api.factory.exception.ExternalModuleLoadFailedException;
|
||||
import work.slhaf.partner.api.factory.exception.ExternalModulePathNotExistException;
|
||||
import work.slhaf.partner.api.factory.module.ModuleCheckFactory;
|
||||
import work.slhaf.partner.api.factory.module.ModuleProxyFactory;
|
||||
import work.slhaf.partner.api.factory.module.ModulePreHookExecuteFactory;
|
||||
import work.slhaf.partner.api.factory.module.ModuleProxyFactory;
|
||||
import work.slhaf.partner.api.factory.module.ModuleRegisterFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class AgentRegisterFactory {
|
||||
|
||||
private static List<String> paths = new ArrayList<>();
|
||||
private static final List<URL> urls = new ArrayList<>();
|
||||
|
||||
private AgentRegisterFactory() {
|
||||
}
|
||||
|
||||
public static AgentContext launch(String path) {
|
||||
paths.add(path);
|
||||
AgentRegisterContext registerContext = new AgentRegisterContext(paths);
|
||||
public static AgentContext launch(String packageName) {
|
||||
urls.addAll(packageNameToURL(packageName));
|
||||
AgentRegisterContext registerContext = new AgentRegisterContext(urls);
|
||||
//流程
|
||||
//0. 加载配置
|
||||
new ConfigLoaderFactory().execute(registerContext);
|
||||
@@ -44,17 +47,41 @@ public class AgentRegisterFactory {
|
||||
new ModulePreHookExecuteFactory().execute(registerContext);
|
||||
|
||||
AgentContext agentContext = new AgentContext();
|
||||
BeanUtil.copyProperties(registerContext,agentContext);
|
||||
BeanUtil.copyProperties(registerContext, agentContext);
|
||||
return agentContext;
|
||||
}
|
||||
|
||||
//TODO 也需要可指定路径,当前只是新增了可扫描包
|
||||
public static void addScanPath(String path) {
|
||||
File file = new File(path);
|
||||
if (!file.exists() || !file.isDirectory()) {
|
||||
throw new ExternalModulePathNotExistException("不存在的外部模块目录: "+path);
|
||||
}
|
||||
paths.add(path);
|
||||
/**
|
||||
* 添加可扫描包
|
||||
* @param packageName 指定的包名
|
||||
*/
|
||||
public static void addScanPackage(String packageName) {
|
||||
urls.addAll(packageNameToURL(packageName));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加外部模块目录
|
||||
* @param externalPackagePath 指定的外部模块目录路径
|
||||
*/
|
||||
public static void addScanDir(String externalPackagePath) {
|
||||
File file = new File(externalPackagePath);
|
||||
if (!file.exists() || !file.isDirectory()) {
|
||||
throw new ExternalModulePathNotExistException("不存在的外部模块目录: " + externalPackagePath);
|
||||
}
|
||||
try {
|
||||
for (File f : file.listFiles()) {
|
||||
if (f.getName().endsWith(".jar")) {
|
||||
urls.add(f.toURI().toURL());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new ExternalModuleLoadFailedException("外部模块URL获取失败: " + externalPackagePath, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<URL> packageNameToURL(String packageName) {
|
||||
return ClasspathHelper.forPackage(packageName).stream().toList();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -2,13 +2,14 @@ package work.slhaf.partner.api.factory.capability;
|
||||
|
||||
import org.reflections.Reflections;
|
||||
import work.slhaf.partner.api.common.util.AgentUtil;
|
||||
import work.slhaf.partner.api.factory.AgentBaseFactory;
|
||||
import work.slhaf.partner.api.factory.capability.annotation.*;
|
||||
import work.slhaf.partner.api.factory.capability.exception.DuplicateCapabilityException;
|
||||
import work.slhaf.partner.api.factory.capability.exception.UnMatchedCapabilityException;
|
||||
import work.slhaf.partner.api.factory.capability.exception.UnMatchedCapabilityMethodException;
|
||||
import work.slhaf.partner.api.factory.capability.exception.UnMatchedCoordinatedMethodException;
|
||||
import work.slhaf.partner.api.factory.entity.AgentBaseFactory;
|
||||
import work.slhaf.partner.api.factory.entity.AgentRegisterContext;
|
||||
import work.slhaf.partner.api.factory.context.AgentRegisterContext;
|
||||
import work.slhaf.partner.api.factory.context.CapabilityFactoryContext;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
@@ -28,9 +29,10 @@ public class CapabilityCheckFactory extends AgentBaseFactory {
|
||||
|
||||
@Override
|
||||
protected void setVariables(AgentRegisterContext context) {
|
||||
CapabilityFactoryContext factoryContext = context.getCapabilityFactoryContext();
|
||||
reflections = context.getReflections();
|
||||
cores = context.getCores();
|
||||
capabilities = context.getCapabilities();
|
||||
cores = factoryContext.getCores();
|
||||
capabilities = factoryContext.getCapabilities();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package work.slhaf.partner.api.factory.capability;
|
||||
|
||||
import org.reflections.Reflections;
|
||||
import work.slhaf.partner.api.factory.AgentBaseFactory;
|
||||
import work.slhaf.partner.api.factory.capability.annotation.Capability;
|
||||
import work.slhaf.partner.api.factory.capability.annotation.InjectCapability;
|
||||
import work.slhaf.partner.api.factory.capability.annotation.ToCoordinated;
|
||||
import work.slhaf.partner.api.factory.capability.exception.ProxySetFailedExceptionCapability;
|
||||
import work.slhaf.partner.api.factory.entity.AgentBaseFactory;
|
||||
import work.slhaf.partner.api.factory.entity.AgentRegisterContext;
|
||||
import work.slhaf.partner.api.factory.context.AgentRegisterContext;
|
||||
import work.slhaf.partner.api.factory.context.CapabilityFactoryContext;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Proxy;
|
||||
@@ -28,10 +29,11 @@ public class CapabilityInjectFactory extends AgentBaseFactory {
|
||||
|
||||
@Override
|
||||
protected void setVariables(AgentRegisterContext context) {
|
||||
CapabilityFactoryContext factoryContext = context.getCapabilityFactoryContext();
|
||||
reflections = context.getReflections();
|
||||
coordinatedMethodsRouterTable = context.getCoordinatedMethodsRouterTable();
|
||||
methodsRouterTable = context.getMethodsRouterTable();
|
||||
capabilityHolderInstances = context.getCapabilityHolderInstances();
|
||||
coordinatedMethodsRouterTable = factoryContext.getCoordinatedMethodsRouterTable();
|
||||
methodsRouterTable = factoryContext.getMethodsRouterTable();
|
||||
capabilityHolderInstances = factoryContext.getCapabilityHolderInstances();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package work.slhaf.partner.api.factory.capability;
|
||||
|
||||
import org.reflections.Reflections;
|
||||
import work.slhaf.partner.api.factory.AgentBaseFactory;
|
||||
import work.slhaf.partner.api.factory.capability.annotation.*;
|
||||
import work.slhaf.partner.api.factory.capability.exception.CapabilityFactoryExecuteFailedException;
|
||||
import work.slhaf.partner.api.factory.capability.exception.CoreInstancesCreateFailedExceptionCapability;
|
||||
import work.slhaf.partner.api.factory.capability.exception.DuplicateMethodException;
|
||||
import work.slhaf.partner.api.factory.entity.AgentBaseFactory;
|
||||
import work.slhaf.partner.api.factory.entity.AgentRegisterContext;
|
||||
import work.slhaf.partner.api.factory.context.AgentRegisterContext;
|
||||
import work.slhaf.partner.api.factory.context.CapabilityFactoryContext;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
@@ -35,13 +36,14 @@ public final class CapabilityRegisterFactory extends AgentBaseFactory {
|
||||
|
||||
@Override
|
||||
protected void setVariables(AgentRegisterContext context) {
|
||||
CapabilityFactoryContext factoryContext = context.getCapabilityFactoryContext();
|
||||
reflections = context.getReflections();
|
||||
methodsRouterTable = context.getMethodsRouterTable();
|
||||
coordinatedMethodsRouterTable = context.getCoordinatedMethodsRouterTable();
|
||||
capabilityCoreInstances = context.getCapabilityCoreInstances();
|
||||
cores = context.getCores();
|
||||
capabilities = context.getCapabilities();
|
||||
capabilityHolderInstances = context.getCapabilityHolderInstances();
|
||||
methodsRouterTable = factoryContext.getMethodsRouterTable();
|
||||
coordinatedMethodsRouterTable = factoryContext.getCoordinatedMethodsRouterTable();
|
||||
capabilityCoreInstances = factoryContext.getCapabilityCoreInstances();
|
||||
cores = factoryContext.getCores();
|
||||
capabilities = factoryContext.getCapabilities();
|
||||
capabilityHolderInstances = factoryContext.getCapabilityHolderInstances();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -2,9 +2,10 @@ package work.slhaf.partner.api.factory.config;
|
||||
|
||||
import lombok.Setter;
|
||||
import work.slhaf.partner.api.common.chat.pojo.Message;
|
||||
import work.slhaf.partner.api.factory.AgentBaseFactory;
|
||||
import work.slhaf.partner.api.factory.config.pojo.ModelConfig;
|
||||
import work.slhaf.partner.api.factory.entity.AgentBaseFactory;
|
||||
import work.slhaf.partner.api.factory.entity.AgentRegisterContext;
|
||||
import work.slhaf.partner.api.factory.context.AgentRegisterContext;
|
||||
import work.slhaf.partner.api.factory.context.ConfigFactoryContext;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -18,8 +19,9 @@ public class ConfigLoaderFactory extends AgentBaseFactory {
|
||||
|
||||
@Override
|
||||
protected void setVariables(AgentRegisterContext context) {
|
||||
modelConfigMap = context.getModelConfigMap();
|
||||
modelPromptMap = context.getModelPromptMap();
|
||||
ConfigFactoryContext factoryContext = context.getConfigFactoryContext();
|
||||
modelConfigMap = factoryContext.getModelConfigMap();
|
||||
modelPromptMap = factoryContext.getModelPromptMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package work.slhaf.partner.api.factory.context;
|
||||
|
||||
import lombok.Data;
|
||||
import org.reflections.Reflections;
|
||||
import org.reflections.scanners.Scanners;
|
||||
import org.reflections.util.ConfigurationBuilder;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class AgentRegisterContext {
|
||||
private Reflections reflections;
|
||||
private CapabilityFactoryContext capabilityFactoryContext = new CapabilityFactoryContext();
|
||||
private ConfigFactoryContext configFactoryContext = new ConfigFactoryContext();
|
||||
private ModuleFactoryContext moduleFactoryContext = new ModuleFactoryContext();
|
||||
|
||||
public AgentRegisterContext(List<URL> urls) {
|
||||
reflections = new Reflections(new ConfigurationBuilder().setScanners(
|
||||
Scanners.FieldsAnnotated,
|
||||
Scanners.SubTypes,
|
||||
Scanners.MethodsAnnotated,
|
||||
Scanners.TypesAnnotated
|
||||
)
|
||||
.setUrls(urls)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package work.slhaf.partner.api.factory.context;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Data
|
||||
public class CapabilityFactoryContext {
|
||||
private final HashMap<String, Function<Object[], Object>> methodsRouterTable = new HashMap<>();
|
||||
private final HashMap<String, Function<Object[], Object>> coordinatedMethodsRouterTable = new HashMap<>();
|
||||
private final HashMap<Class<?>, Object> capabilityCoreInstances = new HashMap<>();
|
||||
private final HashMap<Class<?>, Object> capabilityHolderInstances = new HashMap<>();
|
||||
private Set<Class<?>> cores;
|
||||
private Set<Class<?>> capabilities;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package work.slhaf.partner.api.factory.context;
|
||||
|
||||
import lombok.Data;
|
||||
import work.slhaf.partner.api.common.chat.pojo.Message;
|
||||
import work.slhaf.partner.api.factory.config.pojo.ModelConfig;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class ConfigFactoryContext {
|
||||
private HashMap<String, List<Message>> modelPromptMap = new HashMap<>();
|
||||
private HashMap<String, ModelConfig> modelConfigMap = new HashMap<>();
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package work.slhaf.partner.api.factory.context;
|
||||
|
||||
import lombok.Data;
|
||||
import work.slhaf.partner.api.factory.module.pojo.MetaMethod;
|
||||
import work.slhaf.partner.api.factory.module.pojo.MetaModule;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Data
|
||||
public class ModuleFactoryContext {
|
||||
private List<MetaModule> moduleList = new ArrayList<>();
|
||||
private HashMap<Class<?>,Set<MetaMethod>> preHookMethods = new HashMap<>();
|
||||
private HashMap<Class<?>,Set<MetaMethod>> postHookMethods = new HashMap<>();
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package work.slhaf.partner.api.factory.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import org.reflections.Reflections;
|
||||
import org.reflections.scanners.Scanners;
|
||||
import org.reflections.util.ConfigurationBuilder;
|
||||
import work.slhaf.partner.api.common.chat.pojo.Message;
|
||||
import work.slhaf.partner.api.factory.config.pojo.ModelConfig;
|
||||
import work.slhaf.partner.api.factory.module.pojo.MetaModule;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Data
|
||||
public class AgentRegisterContext {
|
||||
private Reflections reflections;
|
||||
private final HashMap<String, Function<Object[], Object>> methodsRouterTable = new HashMap<>();
|
||||
private final HashMap<String, Function<Object[], Object>> coordinatedMethodsRouterTable = new HashMap<>();
|
||||
private final HashMap<Class<?>, Object> capabilityCoreInstances = new HashMap<>();
|
||||
private final HashMap<Class<?>, Object> capabilityHolderInstances = new HashMap<>();
|
||||
private Set<Class<?>> cores;
|
||||
private Set<Class<?>> capabilities;
|
||||
private HashMap<String, List<Message>> modelPromptMap = new HashMap<>();
|
||||
private HashMap<String, ModelConfig> modelConfigMap = new HashMap<>();
|
||||
private List<MetaModule> moduleList = new ArrayList<>();
|
||||
|
||||
public AgentRegisterContext(List<String> paths) {
|
||||
reflections = new Reflections(new ConfigurationBuilder().setScanners(
|
||||
Scanners.FieldsAnnotated,
|
||||
Scanners.SubTypes,
|
||||
Scanners.MethodsAnnotated,
|
||||
Scanners.TypesAnnotated
|
||||
)
|
||||
.forPackages(paths.toArray(paths.toArray(new String[0])))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package work.slhaf.partner.api.factory.exception;
|
||||
|
||||
public class AgentRegisterFactoryFailedException extends RuntimeException {
|
||||
public AgentRegisterFactoryFailedException(String message, Throwable cause) {
|
||||
super("AgentRegisterFactory 执行失败: " + message, cause);
|
||||
}
|
||||
|
||||
public AgentRegisterFactoryFailedException(String message) {
|
||||
super("AgentRegisterFactory 执行失败: " + message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package work.slhaf.partner.api.factory.exception;
|
||||
|
||||
public class ExternalModuleLoadFailedException extends AgentRegisterFactoryFailedException{
|
||||
public ExternalModuleLoadFailedException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public ExternalModuleLoadFailedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
package work.slhaf.partner.api.factory.exception;
|
||||
|
||||
public class ExternalModulePathNotExistException extends RuntimeException {
|
||||
public class ExternalModulePathNotExistException extends AgentRegisterFactoryFailedException {
|
||||
public ExternalModulePathNotExistException(String message) {
|
||||
super("AgentRegisterFactory 执行失败: " + message);
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ExternalModulePathNotExistException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package work.slhaf.partner.api.factory.module;
|
||||
|
||||
import org.reflections.Reflections;
|
||||
import work.slhaf.partner.api.factory.AgentBaseFactory;
|
||||
import work.slhaf.partner.api.factory.config.ModelConfigManager;
|
||||
import work.slhaf.partner.api.factory.entity.AgentBaseFactory;
|
||||
import work.slhaf.partner.api.factory.entity.AgentRegisterContext;
|
||||
import work.slhaf.partner.api.factory.context.AgentRegisterContext;
|
||||
import work.slhaf.partner.api.factory.module.annotation.After;
|
||||
import work.slhaf.partner.api.factory.module.annotation.AgentModule;
|
||||
import work.slhaf.partner.api.factory.module.annotation.Before;
|
||||
@@ -28,14 +28,27 @@ public class ModuleCheckFactory extends AgentBaseFactory {
|
||||
|
||||
@Override
|
||||
protected void run() {
|
||||
Set<Class<?>> types = reflections.getTypesAnnotatedWith(AgentModule.class);
|
||||
//检查注解AgentModule所在类是否继承了AgentInteractionModule
|
||||
agentModuleAnnotationCheck();
|
||||
agentModuleAnnotationCheck(types);
|
||||
//检查AgentModule是否具备无参构造方法
|
||||
moduleConstructorsCheck(types);
|
||||
//检查hook注解所在方法是否位于AgentInteractionModule子类/AgentInteractionSubModule子类/ActivateModel子类
|
||||
hookLocationCheck();
|
||||
//检查实现了ActivateModel的模块数量、名称与prompt是否一致
|
||||
activateModelImplCheck();
|
||||
}
|
||||
|
||||
private void moduleConstructorsCheck(Set<Class<?>> types) {
|
||||
for (Class<?> type : types) {
|
||||
try {
|
||||
type.getConstructor();
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new ModuleCheckException("缺少无参构造方法的模块: " + type.getSimpleName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void activateModelImplCheck() {
|
||||
try {
|
||||
Set<Class<? extends ActivateModel>> types = reflections.getSubTypesOf(ActivateModel.class);
|
||||
@@ -47,10 +60,10 @@ public class ModuleCheckFactory extends AgentBaseFactory {
|
||||
Set<String> promptKeySet = ModelConfigManager.INSTANCE.getModelPromptMap().keySet();
|
||||
if (!promptKeySet.containsAll(modelKeySet)) {
|
||||
modelKeySet.removeAll(promptKeySet);
|
||||
throw new ModuleCheckException("存在未配置Prompt的ActivateModel实现! 缺少Prompt的ModelKey列表: "+ modelKeySet);
|
||||
throw new ModuleCheckException("存在未配置Prompt的ActivateModel实现! 缺少Prompt的ModelKey列表: " + modelKeySet);
|
||||
}
|
||||
}catch (Exception e) {
|
||||
throw new ModuleCheckException("ActivateModel 检测出错",e);
|
||||
} catch (Exception e) {
|
||||
throw new ModuleCheckException("ActivateModel 检测出错", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,12 +102,11 @@ public class ModuleCheckFactory extends AgentBaseFactory {
|
||||
if (ActivateModel.class.isAssignableFrom(type)) {
|
||||
continue;
|
||||
}
|
||||
throw new ModuleCheckException("在不支持的类中使用了hook注解: "+type.getSimpleName());
|
||||
throw new ModuleCheckException("在不支持的类中使用了hook注解: " + type.getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
private void agentModuleAnnotationCheck() {
|
||||
Set<Class<?>> types = reflections.getTypesAnnotatedWith(AgentModule.class);
|
||||
private void agentModuleAnnotationCheck(Set<Class<?>> types) {
|
||||
for (Class<?> type : types) {
|
||||
if (type.isAnnotation()) {
|
||||
continue;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package work.slhaf.partner.api.factory.module;
|
||||
|
||||
import work.slhaf.partner.api.factory.entity.AgentBaseFactory;
|
||||
import work.slhaf.partner.api.factory.entity.AgentRegisterContext;
|
||||
import work.slhaf.partner.api.factory.AgentBaseFactory;
|
||||
import work.slhaf.partner.api.factory.context.AgentRegisterContext;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
|
||||
@@ -1,21 +1,96 @@
|
||||
package work.slhaf.partner.api.factory.module;
|
||||
|
||||
import work.slhaf.partner.api.factory.entity.AgentBaseFactory;
|
||||
import work.slhaf.partner.api.factory.entity.AgentRegisterContext;
|
||||
import net.bytebuddy.ByteBuddy;
|
||||
import net.bytebuddy.implementation.MethodDelegation;
|
||||
import net.bytebuddy.implementation.bind.annotation.*;
|
||||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
import work.slhaf.partner.api.factory.AgentBaseFactory;
|
||||
import work.slhaf.partner.api.factory.context.AgentRegisterContext;
|
||||
import work.slhaf.partner.api.factory.context.ModuleFactoryContext;
|
||||
import work.slhaf.partner.api.factory.module.exception.ModuleInstanceGenerateFailedException;
|
||||
import work.slhaf.partner.api.factory.module.exception.ModuleProxyGenerateFailedException;
|
||||
import work.slhaf.partner.api.factory.module.pojo.MetaMethod;
|
||||
import work.slhaf.partner.api.factory.module.pojo.MetaModule;
|
||||
import work.slhaf.partner.api.flow.abstracts.AgentInteractionModule;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* 通过扫描注解<code>@Before</code>,获取到各个模块的后hook逻辑并通过动态代理添加到执行逻辑之后
|
||||
*/
|
||||
public class ModuleProxyFactory extends AgentBaseFactory {
|
||||
|
||||
private List<MetaModule> moduleList;
|
||||
private HashMap<Class<?>, Set<MetaMethod>> postHookMethods;
|
||||
|
||||
@Override
|
||||
protected void setVariables(AgentRegisterContext context) {
|
||||
|
||||
ModuleFactoryContext factoryContext = context.getModuleFactoryContext();
|
||||
moduleList = factoryContext.getModuleList();
|
||||
postHookMethods = factoryContext.getPostHookMethods();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
|
||||
//TODO 通过动态代理生成实例、添加PostHook逻辑
|
||||
//TODO 生成实例、并通过动态代理添加PostHook逻辑
|
||||
generateInstances();
|
||||
setPostHookProxy();
|
||||
}
|
||||
|
||||
private void setPostHookProxy() {
|
||||
for (MetaModule module : moduleList) {
|
||||
Class<?> clazz = module.getClazz();
|
||||
try {
|
||||
Class<?> proxyClass = new ByteBuddy()
|
||||
.subclass(clazz)
|
||||
.method(ElementMatchers.isOverriddenFrom(AgentInteractionModule.class))
|
||||
.intercept(MethodDelegation.to(new ModuleProxyInterceptor(postHookMethods.get(clazz).stream().sorted(Comparator.comparing(MetaMethod::getOrder)).toList())))
|
||||
.make()
|
||||
.load(ModuleProxyFactory.class.getClassLoader())
|
||||
.getLoaded();
|
||||
|
||||
AgentInteractionModule interactionModule = (AgentInteractionModule) proxyClass.getConstructor().newInstance();
|
||||
//TODO 检测代理写法是否正确
|
||||
//TODO 添加ModuleManager,负责统一管理Module的加载、卸载
|
||||
} catch (Exception e) {
|
||||
throw new ModuleProxyGenerateFailedException("创建代理对象失败: " + clazz.getSimpleName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void generateInstances() {
|
||||
for (MetaModule metaModule : moduleList) {
|
||||
try {
|
||||
Class<?> clazz = metaModule.getClazz();
|
||||
Object instance = clazz.getConstructor().newInstance();
|
||||
metaModule.setInstance(instance);
|
||||
} catch (Exception e) {
|
||||
throw new ModuleInstanceGenerateFailedException("模块实例构造失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ModuleProxyInterceptor {
|
||||
|
||||
private List<MetaMethod> postHookMethods;
|
||||
|
||||
private ModuleProxyInterceptor(List<MetaMethod> postHookMethods) {
|
||||
this.postHookMethods = postHookMethods;
|
||||
}
|
||||
|
||||
@RuntimeType
|
||||
public Object intercept(@Origin Method method, @AllArguments Object[] allArguments, @SuperCall Callable<?> zuper, @This Object proxy) throws Exception {
|
||||
Object res = zuper.call();
|
||||
for (MetaMethod metaMethod : postHookMethods) {
|
||||
metaMethod.getMethod().invoke(proxy, allArguments);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
package work.slhaf.partner.api.factory.module;
|
||||
|
||||
import org.reflections.Reflections;
|
||||
import work.slhaf.partner.api.factory.entity.AgentBaseFactory;
|
||||
import work.slhaf.partner.api.factory.entity.AgentRegisterContext;
|
||||
import work.slhaf.partner.api.factory.AgentBaseFactory;
|
||||
import work.slhaf.partner.api.factory.context.AgentRegisterContext;
|
||||
import work.slhaf.partner.api.factory.context.ModuleFactoryContext;
|
||||
import work.slhaf.partner.api.factory.module.annotation.After;
|
||||
import work.slhaf.partner.api.factory.module.annotation.AgentModule;
|
||||
import work.slhaf.partner.api.factory.module.annotation.Before;
|
||||
import work.slhaf.partner.api.factory.module.pojo.MetaMethod;
|
||||
import work.slhaf.partner.api.factory.module.pojo.MetaModule;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 负责扫描<code>@Module</code>注解获取模块实例
|
||||
@@ -18,15 +20,63 @@ public class ModuleRegisterFactory extends AgentBaseFactory {
|
||||
|
||||
private Reflections reflections;
|
||||
private List<MetaModule> moduleList;
|
||||
private HashMap<Class<?>, Set<MetaMethod>> postHookMethods;
|
||||
private HashMap<Class<?>, Set<MetaMethod>> preHookMethods;
|
||||
|
||||
@Override
|
||||
protected void setVariables(AgentRegisterContext context) {
|
||||
ModuleFactoryContext factoryContext = context.getModuleFactoryContext();
|
||||
reflections = context.getReflections();
|
||||
moduleList = context.getModuleList();
|
||||
moduleList = factoryContext.getModuleList();
|
||||
postHookMethods = factoryContext.getPostHookMethods();
|
||||
preHookMethods = factoryContext.getPreHookMethods();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run() {
|
||||
registerModuleList();
|
||||
registerHookSet();
|
||||
}
|
||||
|
||||
private void registerHookSet() {
|
||||
setPostHookMethods();
|
||||
setPreHookMethods();
|
||||
}
|
||||
|
||||
private void setPreHookMethods() {
|
||||
Set<Method> methods = reflections.getMethodsAnnotatedWith(After.class);
|
||||
for (Method method : methods) {
|
||||
MetaMethod metaMethod = new MetaMethod();
|
||||
metaMethod.setMethod(method);
|
||||
metaMethod.setOrder(method.getAnnotation(After.class).order());
|
||||
|
||||
addMetaMethod(method, metaMethod, postHookMethods);
|
||||
}
|
||||
}
|
||||
|
||||
private void setPostHookMethods() {
|
||||
Set<Method> methods = reflections.getMethodsAnnotatedWith(Before.class);
|
||||
for (Method method : methods) {
|
||||
MetaMethod metaMethod = new MetaMethod();
|
||||
metaMethod.setMethod(method);
|
||||
metaMethod.setOrder(method.getAnnotation(Before.class).order());
|
||||
|
||||
addMetaMethod(method, metaMethod, preHookMethods);
|
||||
}
|
||||
}
|
||||
|
||||
private void addMetaMethod(Method method, MetaMethod metaMethod, HashMap<Class<?>, Set<MetaMethod>> preHookMethods) {
|
||||
Class<?> clazz = method.getDeclaringClass();
|
||||
if (preHookMethods.containsKey(clazz)) {
|
||||
preHookMethods.get(clazz).add(metaMethod);
|
||||
}else {
|
||||
HashSet<MetaMethod> metaMethods = new HashSet<>();
|
||||
metaMethods.add(metaMethod);
|
||||
preHookMethods.put(clazz, metaMethods);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerModuleList() {
|
||||
//反射扫描获取@AgentModule所在类, 该部分为Agent流程执行模块
|
||||
Set<Class<?>> modules = reflections.getTypesAnnotatedWith(AgentModule.class);
|
||||
for (Class<?> module : modules) {
|
||||
@@ -38,5 +88,6 @@ public class ModuleRegisterFactory extends AgentBaseFactory {
|
||||
moduleList.add(metaModule);
|
||||
}
|
||||
moduleList.sort(Comparator.comparing(MetaModule::getOrder));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package work.slhaf.partner.api.factory.module.exception;
|
||||
|
||||
public class ModuleInstanceGenerateFailedException extends ModuleFactoryFailedException{
|
||||
public ModuleInstanceGenerateFailedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ModuleInstanceGenerateFailedException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package work.slhaf.partner.api.factory.module.exception;
|
||||
|
||||
public class ModuleProxyGenerateFailedException extends ModuleFactoryFailedException{
|
||||
public ModuleProxyGenerateFailedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ModuleProxyGenerateFailedException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package work.slhaf.partner.api.factory.module.pojo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
@Data
|
||||
public class MetaMethod {
|
||||
private int order;
|
||||
private Method method;
|
||||
}
|
||||
Reference in New Issue
Block a user