mirror of
https://github.com/slhaf/Partner.git
synced 2026-05-12 08:43:02 +08:00
refactor(framework): migrate capability injection to Kotlin CapabilityInjectorFactory and inject capability instances directly into components
This commit is contained in:
@@ -2,7 +2,7 @@ package work.slhaf.partner.api.agent.factory;
|
||||
|
||||
import org.reflections.util.ClasspathHelper;
|
||||
import work.slhaf.partner.api.agent.factory.capability.CapabilityAnnotationValidatorFactory;
|
||||
import work.slhaf.partner.api.agent.factory.capability.CapabilityInjectFactory;
|
||||
import work.slhaf.partner.api.agent.factory.capability.CapabilityInjectorFactory;
|
||||
import work.slhaf.partner.api.agent.factory.capability.CapabilityRegisterFactory;
|
||||
import work.slhaf.partner.api.agent.factory.component.ComponentAnnotationValidatorFactory;
|
||||
import work.slhaf.partner.api.agent.factory.component.ComponentInjectorFactory;
|
||||
@@ -50,8 +50,8 @@ public class AgentRegisterFactory {
|
||||
new CapabilityAnnotationValidatorFactory().execute(registerContext);
|
||||
//5. 根据 Capability 相关的扫描结果构造 Capability 实例
|
||||
new CapabilityRegisterFactory().execute(registerContext);
|
||||
//. 先一步注入Capability,避免因前hook逻辑存在针对能力的引用而报错
|
||||
new CapabilityInjectFactory().execute(registerContext);
|
||||
//6. 将 Capability 实例注入至各个 AgentComponent 中
|
||||
new CapabilityInjectorFactory().execute(registerContext);
|
||||
//. 执行模块PreHook逻辑
|
||||
new ModuleInitHookExecuteFactory().execute(registerContext);
|
||||
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
package work.slhaf.partner.api.agent.factory.capability;
|
||||
|
||||
import org.reflections.Reflections;
|
||||
import work.slhaf.partner.api.agent.factory.AgentBaseFactory;
|
||||
import work.slhaf.partner.api.agent.factory.capability.annotation.Capability;
|
||||
import work.slhaf.partner.api.agent.factory.capability.annotation.InjectCapability;
|
||||
import work.slhaf.partner.api.agent.factory.capability.annotation.ToCoordinated;
|
||||
import work.slhaf.partner.api.agent.factory.capability.exception.CapabilityProxySetFailedException;
|
||||
import work.slhaf.partner.api.agent.factory.component.ModuleInitHookExecuteFactory;
|
||||
import work.slhaf.partner.api.agent.factory.context.AgentRegisterContext;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static work.slhaf.partner.api.agent.util.AgentUtil.methodSignature;
|
||||
|
||||
/**
|
||||
* <h2>Agent启动流程 6</h2>
|
||||
*
|
||||
* <p>负责执行 {@link Capability} 的注入逻辑。</p>
|
||||
*
|
||||
* <p>实现方式:</p>
|
||||
* <ol>
|
||||
* <li>通过动态代理,为 {@link AgentRunningModule} 与 {@link AgentSubModule} 中待注入的
|
||||
* <b>能力接口</b> 类型(即 {@link Capability} 标注的接口类)生成代理对象。
|
||||
* </li>
|
||||
* <li>在代理对象内部,根据调用方法的签名确定路由,将调用转发至对应的具体函数。
|
||||
* </li>
|
||||
* <li>通过此机制,实现了 {@link Capability} 单一语义层面上普通方法与协调方法的统一入口。
|
||||
* </li>
|
||||
* </ol>
|
||||
*
|
||||
* <p>下一步流程请参阅 {@link ModuleInitHookExecuteFactory}</p>
|
||||
*/
|
||||
public class CapabilityInjectFactory extends AgentBaseFactory {
|
||||
|
||||
private Reflections reflections;
|
||||
private HashMap<String, Function<Object[], Object>> coordinatedMethodsRouterTable;
|
||||
private HashMap<String, Function<Object[], Object>> methodsRouterTable;
|
||||
private HashMap<Class<?>, Object> capabilityHolderInstances;
|
||||
|
||||
@Override
|
||||
protected void setVariables(AgentRegisterContext context) {
|
||||
CapabilityFactoryContext factoryContext = context.getCapabilityFactoryContext();
|
||||
reflections = context.getReflections();
|
||||
coordinatedMethodsRouterTable = factoryContext.getCoordinatedMethodsRouterTable();
|
||||
methodsRouterTable = factoryContext.getMethodsRouterTable();
|
||||
capabilityHolderInstances = factoryContext.getCapabilityHolderInstances();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run() {
|
||||
//获取现有的`@InjectCapability`注解所在字段,并获取对应的类,通过动态代理注入对象
|
||||
Set<Field> fields = reflections.getFieldsAnnotatedWith(InjectCapability.class);
|
||||
//在动态代理内部,通过函数路由表调用对应的方法
|
||||
createProxy(fields);
|
||||
}
|
||||
|
||||
private void createProxy(Set<Field> fields) {
|
||||
try {
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
Class<?> fieldType = field.getType();
|
||||
Object instance = Proxy.newProxyInstance(
|
||||
fieldType.getClassLoader(),
|
||||
new Class[]{fieldType},
|
||||
(proxy, method, objects) -> {
|
||||
if (method.isAnnotationPresent(ToCoordinated.class)) {
|
||||
String key = method.getDeclaringClass().getAnnotation(Capability.class).value() + "." + methodSignature(method);
|
||||
return coordinatedMethodsRouterTable.get(key).apply(objects);
|
||||
}
|
||||
String key = fieldType.getAnnotation(Capability.class).value() + "." + methodSignature(method);
|
||||
return methodsRouterTable.get(key).apply(objects);
|
||||
}
|
||||
);
|
||||
field.set(capabilityHolderInstances.get(field.getDeclaringClass()), instance);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new CapabilityProxySetFailedException("代理设置失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package work.slhaf.partner.api.agent.factory.capability
|
||||
|
||||
import work.slhaf.partner.api.agent.factory.AgentBaseFactory
|
||||
import work.slhaf.partner.api.agent.factory.capability.annotation.Capability
|
||||
import work.slhaf.partner.api.agent.factory.capability.annotation.InjectCapability
|
||||
import work.slhaf.partner.api.agent.factory.capability.exception.CapabilityProxySetFailedException
|
||||
import work.slhaf.partner.api.agent.factory.context.AgentContext
|
||||
import work.slhaf.partner.api.agent.factory.context.AgentRegisterContext
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Modifier
|
||||
|
||||
class CapabilityInjectorFactory : AgentBaseFactory() {
|
||||
override fun execute(context: AgentRegisterContext) {
|
||||
val agentContext = context.agentContext
|
||||
val targets = buildTargets(agentContext)
|
||||
targets.forEach { target ->
|
||||
injectCapabilities(target, agentContext.capabilities)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildTargets(agentContext: AgentContext): List<Any> {
|
||||
val moduleInstances = agentContext.modules.values.map { it.instance }
|
||||
return moduleInstances + agentContext.additionalComponents
|
||||
}
|
||||
|
||||
private fun injectCapabilities(
|
||||
target: Any,
|
||||
capabilityMap: Map<String, AgentContext.CapabilityImplementation>
|
||||
) {
|
||||
collectInjectFields(target::class.java).forEach { field ->
|
||||
try {
|
||||
field.isAccessible = true
|
||||
val value = resolveCapabilityInstance(field, capabilityMap, target::class.java)
|
||||
field.set(target, value)
|
||||
} catch (e: CapabilityProxySetFailedException) {
|
||||
throw e
|
||||
} catch (e: Exception) {
|
||||
throw CapabilityProxySetFailedException(
|
||||
"Capability 注入失败: ${target::class.java.name}#${field.name}",
|
||||
e
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveCapabilityInstance(
|
||||
field: Field,
|
||||
capabilityMap: Map<String, AgentContext.CapabilityImplementation>,
|
||||
targetClass: Class<*>
|
||||
): Any {
|
||||
val capability = field.type.getAnnotation(Capability::class.java)
|
||||
?: throw CapabilityProxySetFailedException(
|
||||
"InjectCapability 字段类型未标注 @Capability: ${targetClass.name}#${field.name} -> ${field.type.name}"
|
||||
)
|
||||
|
||||
val capabilityValue = capability.value
|
||||
val implementation = capabilityMap[capabilityValue] ?: throw CapabilityProxySetFailedException(
|
||||
"未找到可注入 Capability 实例: ${targetClass.name}#${field.name} -> $capabilityValue"
|
||||
)
|
||||
if (!field.type.isAssignableFrom(implementation.instance.javaClass)) {
|
||||
throw CapabilityProxySetFailedException(
|
||||
"Capability 实例类型不匹配: ${targetClass.name}#${field.name} -> $capabilityValue"
|
||||
)
|
||||
}
|
||||
return implementation.instance
|
||||
}
|
||||
|
||||
private fun collectInjectFields(clazz: Class<*>): List<Field> {
|
||||
val fields = mutableListOf<Field>()
|
||||
var current: Class<*>? = clazz
|
||||
while (current != null && current != Any::class.java) {
|
||||
current.declaredFields
|
||||
.filter { it.isAnnotationPresent(InjectCapability::class.java) }
|
||||
.filter { !Modifier.isStatic(it.modifiers) }
|
||||
.forEach { fields.add(it) }
|
||||
current = current.superclass
|
||||
}
|
||||
return fields
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user