使用javassist代替反射完成類屬性操作工具類
工作當中經常遇到需要使用反射進行成員變數遍歷的工作,但是使用反射的效率在高併發的情況下會比較低,這裡使用了javassit的方式生成了對應的處理類,通過其例項化物件完成遍歷工作
package com.ylink.ncpc.common.util;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang.text.StrBuilder;
import com.ylink.ncpc.common.pojo.CommonRspPojo;
import javassist.CannotCompileException;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;
import javassist.NotFoundException;
/**
* 描述:使用該工具類替代反射,執行效率提高三倍以上
*
* @author songmengqiang 2015年10月26日
*/
public class FeildUtil1 {
public static void main(String[] args) {
CommonRspPojo c = new CommonRspPojo();
long cc = 1000000;
c.setReturn_code("c");
c.setReturn_msg("m");
test(c, cc);
testTmp(c, cc);
}
private static void test(CommonRspPojo c, long cc) {
final List<String> ss = new ArrayList<>();
long currentTimeMillis0 = System.currentTimeMillis();
FeildUtil1.iterate(c, new FeildCallback() {
@Override
public String busiDesc() {
return "CommonRspPojoTest";
}
@Override
public void busi(String fieldName, Object object) {
ss.add((String) object);
}
});
System.out.println("建立處理類使用的時間(毫秒):" + (System.currentTimeMillis() - currentTimeMillis0));
long currentTimeMillis = System.currentTimeMillis();
for (int i = 0; i < cc; i++) {
FeildUtil1.iterate(c, new FeildCallback() {
@Override
public String busiDesc() {
return "CommonRspPojoTest";
}
@Override
public void busi(String fieldName, Object object) {
ss.add((String) object);
}
});
}
System.out.println(ss.size());
System.out.println("javasist使用時間(毫秒):" + (System.currentTimeMillis() - currentTimeMillis));
}
private static void testTmp(CommonRspPojo c, long cc) {
final List<String> ss1 = new ArrayList<>();
FeildUtil1.iterateTemp(c, new FeildCallback() {
@Override
public String busiDesc() {
return "CommonRspPojoTest1";
}
@Override
public void busi(String fieldName, Object object) {
ss1.add((String) object);
}
});
long currentTimeMillis = System.currentTimeMillis();
for (int i = 0; i < cc; i++) {
FeildUtil1.iterateTemp(c, new FeildCallback() {
@Override
public String busiDesc() {
return "CommonRspPojoTest";
}
@Override
public void busi(String fieldName, Object object) {
ss1.add((String) object);
}
});
}
System.out.println(ss1.size());
System.out.println("反射機制使用時間(毫秒):" + (System.currentTimeMillis() - currentTimeMillis));
}
/**
* 通過反射做業務處理,但是反射的效能消耗會比較大,不推薦使用
*
* @param object
* @param FeildUtil1Callback
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
@Deprecated
public static void iterateTemp(Object object, FeildCallback FeildUtil1Callback) {
try {
Field[] declaredFields = object.getClass().getDeclaredFields();
for (Field field : declaredFields) {
field.setAccessible(true);
String fieldName = field.getName();
Object fieldObj = field.get(object);
FeildUtil1Callback.busi(fieldName, fieldObj);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 描述:該遍歷器用來遍歷所有的成員變數,如果該成員變數有對應的get方法則會呼叫 callback進行處理
*
* @param o
* @param fCallback
*/
public static void iterate(Object o, FeildCallback fCallback) {
String busiDesc = fCallback.busiDesc();
FeildHandlerInterface FeildUtil1Interface = handlerMap.get(busiDesc);
if (FeildUtil1Interface == null) {
try {
FeildUtil1Interface = createHandler(o, busiDesc);
} catch (Exception e) {
e.printStackTrace();
return;
}
}
FeildUtil1Interface.iterate(o, fCallback);
}
@SuppressWarnings("unchecked")
private static synchronized FeildHandlerInterface createHandler(Object o, String busiDesc)
throws NotFoundException, CannotCompileException, InstantiationException, IllegalAccessException {
//===start 當一個執行緒已經建立完畢,另一個執行緒剛好進入到該方法時則直接返回建立的結果
FeildHandlerInterface FeildUtil1Interface = handlerMap.get(busiDesc);
if (FeildUtil1Interface != null) {
return FeildUtil1Interface;
}
//===end
// 反射獲取屬性名陣列
Class<? extends Object> class1 = o.getClass();
int busiDescHash = busiDesc.hashCode();
Field[] fields = class1.getDeclaredFields();
Map<String, Method> methodMap = new HashMap<>();
Method[] methods = class1.getMethods();
for (Method method : methods) {
methodMap.put(method.getName(), method);
}
// 反射獲取類名
String classPath = class1.getName();
String name = FeildCallback.class.getName();
// 建立類繼承FeildUtil1Interface
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(FeildUtil1.class));
CtClass newClass = pool.makeClass("com.ylink.ncpc.common.util.Handler" + busiDescHash);
CtClass[] list = new CtClass[] { pool.getCtClass("com.ylink.ncpc.common.util.FeildHandlerInterface") };
newClass.setInterfaces(list);
// 建立方法實現FeildUtil1Interface.iterate(o, fCallback);
String methodString = "public void iterate(Object o," + name + " fCallback){\n" + " " + classPath + " tt=("
+ classPath + ")o;\n";
for (Field field : fields) {
if (methodMap.containsKey("get" + capitalise(field.getName()))) {
methodString += "fCallback.busi(\"" + field.getName() + "\",tt.get" + capitalise(field.getName())
+ "());\n";
}
}
methodString += "}\n";
CtMethod f = CtNewMethod.make(methodString, newClass);
newClass.addMethod(f);
Class<FeildHandlerInterface> realClass = newClass.toClass();
FeildHandlerInterface newInstance = realClass.newInstance();
handlerMap.put(busiDesc, newInstance);
return newInstance;
}
/**
* 首字母大寫
*
* @param str
* @return
*/
private static String capitalise(String str) {
int strLen;
if (str == null || (strLen = str.length()) == 0) {
return str;
}
return new StrBuilder(strLen).append(Character.toTitleCase(str.charAt(0))).append(str.substring(1)).toString();
}
private static Map<String, FeildHandlerInterface> handlerMap = new ConcurrentHashMap<String, FeildHandlerInterface>();
}
interface FeildHandlerInterface {
public abstract void iterate(Object o, FeildCallback fCallback);
}
package com.ylink.ncpc.common.util;
public abstract class FeildCallback{
/**
* 描述:該方法實現具體的業務
* @param fieldName
* @param object
*/
public abstract void busi(String fieldName,Object object);
/**
* 描述必須全域性唯一,如果存在一樣的定義,那可能會有衝突。
* 不能返回空。。
* @return
*/
public abstract String busiDesc();
}