Netty 游戏开发 自动注入handler以及通过Javassist提高反射效率

通过路径扫描,扫描出该包或子包中标有@CmdHandler注解的类,然后通过反射,将其实例化后缓存。

try {
            Set<Class> classes = ScanPackageUtil.ScanPackage("org.tinygame.herostory2", CmdHandler.class);
            if(classes == null){
                logger.error("自动添加handler扫描包失败");
            }
            for (Class aClass : classes) {
                System.out.println("^^^ " + aClass.getSimpleName() + " ^^^");

                Type[] genericInterfaces = aClass.getGenericInterfaces();
                for (Type genericInterface : genericInterfaces) {
                    if(!(genericInterface instanceof ParameterizedType)){
                        continue;
                    }
                    Type[] actualTypeArguments = ((ParameterizedType) genericInterface).getActualTypeArguments();
                    for (Type actualTypeArgument : actualTypeArguments) {
                        String s = actualTypeArgument.getTypeName();
                        System.out.println("获取到接口<? extend xx>类型名:" + s);
                        Class<?> aClass2 = Class.forName(s);
                        ICmdHandler iCmdHandler = (ICmdHandler) aClass.newInstance();
                        handlerMap.put(aClass2, iCmdHandler);
                    }
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        }

通过扫描包路径,将配置有@CmdHandler 注解的类自动加到handlerMap当中,实现自动注入handler。

首先来看一下 Mybaties类似的原理,使用原生的jdbc来读取mysql数据库(orm框架模型)

最早的版本
在这里插入图片描述
但是你会发现不太灵活,每次都需要自己一直去写getInt、getString等等

通过注解自动匹配版本(优化)
在这里插入图片描述
在这里插入图片描述
这样做是挺好的,但是似乎性能不是很好,因为我们执行该代码时需要频繁的使用反射。那么可以使用Javassist来优化一下,但是javassist对编码的要求还是有点高的,感觉类似空白写代码的感觉。

通过Javassist优化后
在这里插入图片描述
为什么这个效率就会比较高呢?
我们只有使用EntityHelperFactory创建EntityHelper的时候才使用反射,自动生成需要的字节码,并将需要使用的AbstractEntityHelper缓存起来,也就相当于,一个实体类就使用一次反射,之后的全都使用缓存里的实例来create获取实例,相比每次每个实例都使用反射来说效率大大的提高。

看看具体是如何实现的,需要注意int和Integer是在jdbc中是不会自动帮我们转化的

public class EntityHelperFactory {

    private static Map<Class, AbstractEntityHelper> map = new HashMap<>();

    private EntityHelperFactory() {
    }

    public static AbstractEntityHelper getEntityHelper(Class clazz) throws Exception{
        if(clazz == null){ return null; }
        AbstractEntityHelper entityHelper = map.get(clazz);

        if(entityHelper != null){
            return entityHelper;
        }

        ClassPool classPool = ClassPool.getDefault();

        //导包  自己的实体类 和 数据库包
        // import java.sql.ResultSet
        // import test.entity.UserEntity
        classPool.importPackage(ResultSet.class.getName());
        classPool.importPackage(clazz.getName());

        //获取抽象类
        CtClass ctClass = classPool.getCtClass(AbstractEntityHelper.class.getName());
        //获取实现类名称
        String className = clazz.getName() + "_Helper";

        //相当 public UserEntity_Helper extend AbstractEntityHelper{...
        CtClass helperClazz = classPool.makeClass(className, ctClass);

        //设置空的构造函数 public Entity_Helper{}
        CtConstructor ctConstructor = new CtConstructor(new CtClass[0], helperClazz);
        ctConstructor.setBody("{}");
        helperClazz.addConstructor(ctConstructor);


        //开始 拼接方法
        //TODO:Exception in thread "main" java.lang.VerifyError: (class: org/ormtest/step002/entity/UserEntity_Helper, method: getEntityHelper signature: (Ljava/sql/ResultSet;)Ljava/lang/Object;) Expecting to find object/array on stack
        StringBuilder sb = new StringBuilder();
        sb.append("public Object create(java.sql.ResultSet rs) throws Exception {\n");
        sb.append(clazz.getName())
                .append(" obj = new ")
                .append(clazz.getName())
                .append("();\n");

        Field[] fields = clazz.getFields();
        for (Field f : fields) {

                Column annotation = f.getAnnotation(Column.class);
                if(annotation == null){
                    continue;
                }

                String colName = annotation.name();
                // TODO: 为什么 罪魁祸首是 f.getType().equals(Integer.class)
                // 注意:这里的int和integer互不相同,需要特殊处理
                if(f.getType() == Integer.TYPE){
                    sb.append("obj.")
                            .append(f.getName())
                            .append(" = ")
                            .append("rs.getInt(\"")
                            .append(colName)
                            .append("\");\n");
                } else if(f.getType().equals(Integer.class)){
                    sb.append("obj.")
                            .append(f.getName())
                            .append(" = ")
                            .append("Integer.valueOf(rs.getInt(\"")
                            .append(colName)
                            .append("\"));\n");
                }else if(f.getType().equals(String.class)){
                    sb.append("obj.")
                            .append(f.getName())
                            .append(" = ")
                            .append("rs.getString(\"")
                            .append(colName)
                            .append("\");\n");
                }else{
                    System.out.println(f.getType() + "类型暂时不支持!!!");
                    System.out.println("????? " + Integer.TYPE + "??????" + Integer.class);
                }
        }
        sb.append("return obj;\n")
                .append("}");

        System.out.println(sb.toString());
        //凭借完成后,生成方法
        CtMethod ctMethod = CtMethod.make(sb.toString(), helperClazz);
        //添加到类中
        helperClazz.addMethod(ctMethod);
        //生成字节码文件
        Class aClass = helperClazz.toClass();
        helperClazz.writeFile("d://debug_java");
        AbstractEntityHelper helper = (AbstractEntityHelper)aClass.newInstance();

        map.put(clazz, helper);

        return  helper;

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值