框架集成实战
2026年5月29日 上午9:06:17
EggG 从设计上是框架无关的——它是一套通用的类型分析与元数据提取引擎,任何 Java 项目都可以使用。
本文先给出一套通用集成模板,再分别展示 Snack4(JSON 库)和 Solon(应用框架)的生产集成代码。
1、通用集成模板
集成分为三步:创建单例 → 注册 Handler → 使用。
第一步:创建全局 Eggg 单例,注册 Handler
public class TypeAnalyzer {
private static final Eggg eggg = new Eggg()
.withDigestHandler(TypeAnalyzer::doDigestHandle)
.withAliasHandler(TypeAnalyzer::doAliasHandle);
private static Object doDigestHandle(ClassEggg cw, AnnotatedEggg source, Object ref) {
// 注解解析逻辑
return ref;
}
private static String doAliasHandle(ClassEggg cw, AnnotatedEggg source, String ref) {
// 别名生成逻辑
return ref;
}
public static TypeEggg analyze(Type type) {
return eggg.getTypeEggg(type);
}
public static ClassEggg analyzeClass(Type type) {
return eggg.getTypeEggg(type).getClassEggg();
}
}
第二步:在需要的地方调用
ClassEggg cw = TypeAnalyzer.analyzeClass(MyModel.class);
for (FieldEggg fw : cw.getAllFieldEgggs()) {
if (fw.isStatic()) continue;
String name = fw.getName();
String alias = fw.getAlias();
Object digest = fw.getDigest();
TypeEggg fieldType = fw.getTypeEggg();
// ... 业务逻辑
}
2、实战:Snack4(JSON 库)
Snack4 是一个高性能的 Java JSON 处理库,使用 EggG 完成:
- 序列化时分析字段的泛型类型和注解别名
- 反序列化时匹配构造器、解析参数别名
- 通过 Creator 机制支持自定义对象构建
EgggUtil 实现
package org.noear.snack4.codec.util;
import org.noear.eggg.*;
import org.noear.snack4.annotation.ONodeAttrHolder;
import org.noear.snack4.annotation.ONodeAttr;
import org.noear.snack4.annotation.ONodeCreator;
import java.lang.reflect.*;
public class EgggUtil {
private static final Eggg eggg = new Eggg()
.withCreatorClass(ONodeCreator.class)
.withDigestHandler(EgggUtil::doDigestHandle)
.withAliasHandler(EgggUtil::doAliasHandle);
private static String doAliasHandle(ClassEggg cw, AnnotatedEggg s, String ref) {
if (s.getDigest() instanceof ONodeAttrHolder) {
return ((ONodeAttrHolder) s.getDigest()).getAlias();
} else {
return ref;
}
}
private static Object doDigestHandle(ClassEggg cw, AnnotatedEggg s, Object ref) {
ONodeAttr attr = s.getElement().getAnnotation(ONodeAttr.class);
if (attr == null && ref != null) {
return ref;
}
if (s instanceof FieldEggg) {
return new ONodeAttrHolder(attr, ((Field) s.getElement()).getName());
} else if (s instanceof PropertyMethodEggg) {
return new ONodeAttrHolder(attr,
Property.resolvePropertyName(((Method) s.getElement()).getName()));
} else if (s instanceof ParamEggg) {
return new ONodeAttrHolder(attr, ((Parameter) s.getElement()).getName());
} else {
return null;
}
}
public static TypeEggg getTypeEggg(Type type) {
return eggg.getTypeEggg(type);
}
}
使用场景
// 序列化:遍历字段,按别名输出 JSON 键
TypeEggg typeEggg = EgggUtil.getTypeEggg(clazz);
for (FieldEggg fw : typeEggg.getClassEggg().getAllFieldEgggs()) {
if (fw.isStatic()) continue;
String jsonKey = fw.getAlias(); // 使用别名作为 JSON key
TypeEggg ft = fw.getTypeEggg(); // 字段类型(含泛型)
Object digest = fw.getDigest(); // ONodeAttrHolder
}
4、实战:Solon(应用框架)
Solon 是一个轻量级 Java 应用开发框架,使用 EggG 完成:
- 依赖注入中的类型分析与元数据提取
- 字段注入时解析参数别名和注解
- 通过 ReflectHandler 支持原生编译场景
EgggUtil 实现
package org.noear.solon.core.util;
import org.noear.eggg.*;
import org.noear.solon.core.wrap.FieldSpec;
import org.noear.solon.core.wrap.ParamSpec;
import org.noear.solon.core.wrap.VarSpec;
import java.lang.reflect.*;
public class EgggUtil {
private static final Eggg eggg = new Eggg()
.withAliasHandler(EgggUtil::doAliasHandle)
.withDigestHandler(EgggUtil::doDigestHandle)
.withReflectHandler(new EgggReflectHandler());
private static String doAliasHandle(ClassEggg cw, AnnotatedEggg s, String ref) {
if (s.getDigest() instanceof VarSpec) {
return s.<VarSpec>getDigest().getName();
}
return ref;
}
private static Object doDigestHandle(ClassEggg cw, AnnotatedEggg s, Object ref) {
if (s instanceof FieldEggg) {
return new FieldSpec((FieldEggg) s);
} else if (s instanceof ParamEggg) {
return new ParamSpec((ParamEggg) s);
}
return ref;
}
public static TypeEggg getTypeEggg(Type type) {
return eggg.getTypeEggg(type);
}
public static ClassEggg getClassEggg(Type type) {
return getTypeEggg(type).getClassEggg();
}
}
使用场景
// 依赖注入:分析 Bean 类型的字段和参数
ClassEggg cw = EgggUtil.getClassEggg(beanType);
for (FieldEggg fw : cw.getAllFieldEgggs()) {
FieldSpec spec = fw.getDigest(); // 自定义的 FieldSpec
TypeEggg fieldType = fw.getTypeEggg();
String alias = fw.getAlias(); // 注入名称
}
5、注意事项
Eggg 实例使用全局单例
Eggg 实例是线程安全的,内部使用缓存机制。每次调用都 new 一个新实例会导致同一类型被反复解析,失去缓存优势。
// 推荐
private static final Eggg eggg = new Eggg();
// 不推荐
public TypeEggg analyze(Type type) {
return new Eggg().getTypeEggg(type); // 无缓存
}
Handler 必须在首次查询之前注册
Handler 在元数据创建时执行,元数据会被缓存。如果先调用 getTypeEggg() 再注册 Handler,Handler 不会被执行——因为缓存中已经存在未经 Handler 处理的数据。
// 正确
Eggg eggg = new Eggg()
.withDigestHandler(this::handle)
.withAliasHandler(this::handle);
TypeEggg t = eggg.getTypeEggg(type);
// 错误
Eggg eggg = new Eggg();
TypeEggg t = eggg.getTypeEggg(type); // Handler 未注册
eggg.withDigestHandler(this::handle); // 已缓存,不会触发
缓存清除
在热部署等特殊场景下(如运行时类被替换),可以手动清除缓存:
eggg.clear(); // 清除所有 TypeEggg 和 ClassEggg 缓存
如果需要更精细的清理(例如热插拔项目),也可以按类型、类加载器或包名移除:
eggg.remove(MyPluginClass.class); // 移除指定类型
eggg.removeByClassLoader(pluginClassLoader); // 移除该类加载器下的所有类型
eggg.removeByPackage("com.example.plugin"); // 移除该包下的所有类型
FieldEggg 与 PropertyEggg 的区别
- FieldEggg:直接访问字段(包括 private),适合框架内部使用
- PropertyEggg:通过 getter/setter 访问,适合面向用户的属性模型
// 框架内部:直接字段访问
FieldEggg field = cw.getFieldEgggByName("name");
// 用户 API:走 getter/setter
PropertyEggg prop = cw.getPropertyEgggByName("name");