通过路径扫描,扫描出该包或子包中标有@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;
}
}