Solon v3.10.7

框架集成实战

</> markdown
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 完成:

  1. 序列化时分析字段的泛型类型和注解别名
  2. 反序列化时匹配构造器、解析参数别名
  3. 通过 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 完成:

  1. 依赖注入中的类型分析与元数据提取
  2. 字段注入时解析参数别名和注解
  3. 通过 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");