前言
兩個(gè)月前寫過一篇文章基于Django設(shè)計(jì)的Restful MockServer禁灼,是基于網(wǎng)絡(luò)的轧简。很多人都覺得思路不錯(cuò),但是主要是太麻煩了匾二。本篇博文就根據(jù)Java開發(fā)一個(gè)假數(shù)據(jù)生成器哮独,稱為
JBMock
。
主要功能
1察藐、提供同步皮璧、異步獲取數(shù)據(jù)
2、異步獲取數(shù)據(jù)提供線程切換
原理圖
1分飞、使用反射悴务,獲取UserEntity的屬性和對(duì)應(yīng)注解(Type注解)
2、獲取注解里面的值譬猫,然后使用TypeParser解析注解值讯檐,然后設(shè)置到對(duì)應(yīng)的屬性上
3、使用ThreadDispatcher完成回調(diào)
代碼分析
包結(jié)構(gòu)
代碼
Type注解
package com.august1996.anno;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Type {
String value();
}
這個(gè)注解的意義在于我們給某個(gè)屬性加上這個(gè)注解染服,然后根據(jù)類型去給屬性賦值别洪,例如value為username時(shí),那么這個(gè)屬性就會(huì)被賦上小明柳刮、小紅挖垛、小花等值
TypeParser類型解析器
package com.august1996.core;
public interface TypeParser {
Object parser(String type);
}
該接口的作用是解析
Type注解
的value,返回對(duì)應(yīng)的值
OnMockedCallback回調(diào)
package com.august1996.callback;
import java.util.ArrayList;
public interface OnMockedCallback<T> {
void onMocked(ArrayList<T> listEntity);
}
當(dāng)異步模擬數(shù)據(jù)完成時(shí)秉颗,該回調(diào)帶著結(jié)果被執(zhí)行
ThreadDispatcher線程切換
package com.august1996.thread;
import java.util.ArrayList;
import com.august1996.callback.OnMockedCallback;
public interface ThreadDispatcher {
<T> void dispatcher(ArrayList<T> value, OnMockedCallback<T> callback);
}
該接口完成回調(diào)時(shí)的線程切換痢毒,本項(xiàng)目是JavaSDK的,如果接入Android時(shí)蚕甥,只需要繼承自該接口使用Handler就能完成主線程切換
DefaultDispatcher分配默認(rèn)線程
package com.august1996.thread;
import java.util.ArrayList;
import com.august1996.callback.OnMockedCallback;
public class DefaultDispatcher implements ThreadDispatcher {
@Override
public <T> void dispatcher(ArrayList<T> value, OnMockedCallback<T> callback) {
if (callback != null) {
callback.onMocked(value);
}
}
}
該類是最簡(jiǎn)單的ThreadDispatcher,如果需要在Android中切換主線程哪替,只需要繼承ThreadDispatcher,然后使用Handler切換回主線程就OK了
DispatcherHolder管理類
package com.august1996.thread;
import java.util.HashMap;
import java.util.Map;
public class DispatcherHolder {
private static final Map<Class<? extends ThreadDispatcher>, ThreadDispatcher> sMap;
static {
sMap = new HashMap<>();
register(new DefaultDispatcher());
}
public static void register(ThreadDispatcher dispatcher) {
sMap.put(dispatcher.getClass(), dispatcher);
}
public static void unregister(Class<? extends ThreadDispatcher> clazz) {
sMap.remove(clazz);
}
public static ThreadDispatcher get(Class<? extends ThreadDispatcher> clazz) {
return sMap.get(clazz);
}
}
該類的作用是管理不同類型的ThreadDispatcher菇怀,可以通過注冊(cè)不同的ThreadDispatcher凭舶,使JBMock可以調(diào)用其他自己編寫的ThreadDispatcher
ValueHolder類型數(shù)據(jù)管理器
package com.august1996.parser;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
public class ValueHolder {
private static final Map<String, List<Object>> sMap = new HashMap<String, List<Object>>();
private static final Random sRandom = new Random();
public static void register(String type, Object... value) {
List<Object> list = sMap.get(type);
if (list == null) {
list = new ArrayList<Object>();
sMap.put(type, list);
}
list.addAll(Arrays.asList(value));
}
public static void unregister(String type) {
sMap.remove(type);
}
public static void clear() {
sMap.clear();
}
static Object get(String type) {
List<Object> list = sMap.get(type);
if (list != null && !list.isEmpty()) {
return list.get(sRandom.nextInt(list.size()));
}
return null;
}
}
該類負(fù)責(zé)管理
Type注解
對(duì)應(yīng)的數(shù)據(jù)晌块,例如如果想要當(dāng)屬性的Type的value為username時(shí),JBMock就會(huì)給這個(gè)屬性賦值小明库快、小紅、小花等內(nèi)容钥顽,那么就需要register("username","小明","小紅","小花")
HolderParser解析器
package com.august1996.parser;
import com.august1996.core.TypeParser;
public class HolderParser implements TypeParser {
@Override
public Object parser(String type) {
return ValueHolder.get(type);
}
}
該類為默認(rèn)的Parser之一义屏,結(jié)合
Type注解
和ValueHolder
根據(jù)類型解析數(shù)據(jù)
MockRunnable異步任務(wù)
package com.august1996.core;
import java.util.ArrayList;
import com.august1996.callback.OnMockedCallback;
import com.august1996.thread.DispatcherHolder;
import com.august1996.thread.ThreadDispatcher;
public class MockRunnable<T> implements Runnable {
private Class<T> clazz;
private int size;
private int delay;
private OnMockedCallback<T> callback;
private Class<? extends ThreadDispatcher> threadDispatch;
public MockRunnable(Class<T> clazz, int size, int delay, Class<? extends ThreadDispatcher> threadDispatch,
OnMockedCallback<T> callback) {
super();
this.delay = delay;
this.clazz = clazz;
this.callback = callback;
this.size = size;
this.threadDispatch = threadDispatch;
}
@Override
public void run() {
try {
Thread.sleep(delay);
ArrayList<T> listEntity = Factory.getListEntity(clazz, size);
DispatcherHolder.get(threadDispatch).dispatcher(listEntity, callback);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Factory數(shù)據(jù)生產(chǎn)類
package com.august1996.core;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import com.august1996.anno.Type;
import com.august1996.parser.DefaultParser;
import com.august1996.parser.HolderParser;
public class Factory {
static {
mParser = new HashMap<>();
initDefautParser();
}
private static Map<Class<? extends TypeParser>, TypeParser> mParser;
/**
* 獲取多個(gè)Entity
*
* @param cls
* Entity的類
* @param size
* Entity的數(shù)量
* @return
*/
static <T> ArrayList<T> getListEntity(Class<T> cls, int size) {
ArrayList<T> result = new ArrayList<T>();
for (int i = 0; i < size; i++) {
result.add(getEntity(cls));
}
return result;
}
/**
* 獲取單個(gè)Entity
*
* @param cls
* @return
*/
static <T> T getEntity(Class<T> cls) {
T obj = null;
try {
obj = cls.newInstance();
Field[] declaredFields = cls.getDeclaredFields();
for (Field field : declaredFields) { // 獲取Entity類的所有屬性
field.setAccessible(true);
Annotation[] annotations = field.getAnnotations(); // 獲取屬性的注解
for (Annotation anno : annotations) {
if (anno instanceof Type) {
for (Map.Entry<Class<? extends TypeParser>, TypeParser> parser : mParser.entrySet()) {
Object value = parser.getValue().parser(((Type) anno).value()); // 獲取到Type注解,使用TypeParser去解析類型
if (value != null) {
field.set(obj, value);
}
}
}
}
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return obj;
}
/**
* 初始化默認(rèn)TypeParser
*/
private static void initDefautParser() {
addParser(new HolderParser());
}
public static void addParser(TypeParser typeParser) {
mParser.put(typeParser.getClass(), typeParser);
}
public static TypeParser removeParser(Class<? extends TypeParser> clazz) {
return mParser.remove(clazz);
}
public static void clearParser() {
mParser.clear();
initDefautParser();
}
}
該類主要是用來產(chǎn)生數(shù)據(jù)
JBMock核心類
package com.august1996.core;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.august1996.callback.OnMockedCallback;
import com.august1996.thread.ThreadDispatcher;
public class JBMock {
private static final JBMock sInstance = new JBMock();
public static JBMock getInstance() {
return sInstance;
}
private JBMock() {
mExecutors = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
}
private ExecutorService mExecutors;
public <T> ArrayList<T> syncGet(Class<T> cls, int delay, int size) {
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
e.printStackTrace();
}
return Factory.getListEntity(cls, size);
}
public <T> void asyncGet(Class<T> cls, int delay, int size, Class<? extends ThreadDispatcher> threadDispatcherCls,
OnMockedCallback<T> callback) {
mExecutors.submit(new MockRunnable<T>(cls, size, delay, threadDispatcherCls, callback));
}
}
使用
新建一個(gè)UserEntity
package com.august1996.test;
import com.august1996.anno.Type;
import com.august1996.parser.DefaultType;
public class UserEntity {
@Type("username")
public String username;
@Type("icon")
public String icon;
@Type("gender")
public int gender;
@Type(DefaultType.NOW_TIMESTAMP)
public long regTime;
@Override
public String toString() {
return "UserEntity [username=" + username + ", icon=" + icon + ", gender=" + gender + ", regTime=" + regTime
+ "]";
}
}
測(cè)試代碼
package com.august1996.test;
import java.util.ArrayList;
import com.august1996.callback.OnMockedCallback;
import com.august1996.core.JBMock;
import com.august1996.parser.ValueHolder;
import com.august1996.thread.DefaultDispatcher;
public class TestDemo {
public static void main(String[] args) {
ValueHolder.register("username", "小明", "小紅");
ValueHolder.register("username", "小花");
ValueHolder.register("icon", "http://www.baidu.com/1.jpg", "http://www.baidu.com/2.jpg");
ValueHolder.register("icon", "http://www.baidu.com/3.jpg");
ValueHolder.register("gender", 1);
ValueHolder.register("gender", 0);
ArrayList<UserEntity> list = JBMock.getInstance().syncGet(UserEntity.class, 3000, 10);
for (UserEntity entity : list) {
System.out.println(entity.toString());
}
JBMock.getInstance().asyncGet(UserEntity.class, 3000, 5, DefaultDispatcher.class,
new OnMockedCallback<UserEntity>() {
@Override
public void onMocked(ArrayList<UserEntity> listEntity) {
System.out.println(Thread.currentThread().getName());
for (UserEntity entity : listEntity) {
System.out.println(entity.toString());
}
}
});
}
}
輸出
pool-1-thread-1
UserEntity [username=小花, icon=http://www.baidu.com/2.jpg, gender=0, regTime=1495010339777]
UserEntity [username=小明, icon=http://www.baidu.com/3.jpg, gender=1, regTime=1495010339779]
UserEntity [username=小明, icon=http://www.baidu.com/3.jpg, gender=1, regTime=1495010339779]
UserEntity [username=小紅, icon=http://www.baidu.com/3.jpg, gender=0, regTime=1495010339779]
UserEntity [username=小花, icon=http://www.baidu.com/2.jpg, gender=1, regTime=1495010339779]
DefaultType.NOW_TIMESTAMP是什么
這是我們自定義的一個(gè)TypeParser蜂大,我們使用Factory.addParser添加就OK啦闽铐。
DefaultParser
package com.august1996.parser;
import com.august1996.core.TypeParser;
public class DefaultParser implements TypeParser {
@Override
public Object parser(String type) {
if (DefaultType.NOW_TIMESTAMP.equals(type)) {
return System.currentTimeMillis();
}
return null;
}
}
DefaultType
package com.august1996.parser;
public class DefaultType {
public static final String NOW_TIMESTAMP = "jb_now";
}
可自行擴(kuò)展的地方
需要更多的擴(kuò)展,實(shí)現(xiàn)ThreadDispatcher和TypeParser即可奶浦。