編程習慣

轉Map時要考慮Map的key是否重複

List<Entity>轉爲Map<keyField, valueField>

將一個List實體集合轉換爲以Entity某一個字段爲key,另外一字段爲value映射的Map框架

    /**
     * List轉換爲Map<key字段,val字段/實體>
     */
    public Map<String,Object> getMapByList(List list){
        Map<String,Object> resultMap= new HashMap<String,Object>();  //結果,字段/值的映射map

        if (CollectionUtil.isNotEmpty(list)){   //先判斷list是否爲空 for (Entity entity:list){     //遍歷List
                String keyField= entity.getKeyField();   //
                Object valueField = entity.getValField();   //值,值也能夠爲其餘字段或者整個對象
/********遍歷list的key字段不能直接放入Map中,由於可能有重複的,這樣發現不了問題*********/ if (resultMap.containsKey(keyField)){ //若是key字段的值是有重複的 valueField = resultMap.get(keyField) + StringUtil.SEPARATOR + valueField; //value字段的值爲: 舊的數據<-->新的數據做爲value }
/**********處理可能重複key的狀況結束************/ resultMap.put(keyField,valueField); //最後在將處理後的keyField和valueField放入到Map中去 } }
return resultMap; }

List<Entity>轉爲Map<keyField,List<Entity>>

將List中的實體根據keyField字段分類成Map<keyField,List>ide

     public Map<String,List<Entity>> getMapByList(List<Entity> list){
        Map<String,List<Entity>> resultMap = new HashMap<String,List<Entity>>();   //目標結果Map

        if (CollectionUtil.isNotEmpty(list)){    //判斷是否爲空
            for (Entity entity:list){    //遍歷List集合
                String keyField = entity.getKeyField();    //獲取key字段值
              
                /****************************考慮Map中key值重複的狀況*****************************/
                List<Entity> list;   //根據keyField分組的list
                if (resultMap.containsKey(keyField)){    //若是以前有keyField字段對一個的實體已經放入過List,即已經存在在結果Map中
                    list = resultMap.get(keyField);   //根據keyFiedl獲取Map中對應的List集合
                }else{
                    list = new ArrayList<Entity>();  //這個字段以前沒有放入過實體,沒有List,新建一個List
                }
                list.add(entity);   //放入到keyField對應的List中去
                /*************************考慮Map中key值重複的狀況結束********************************/
                
                resultMap.put(keyField,list);   //放入到Map<keyField,List<Entity>>的映射中
            }
        }
        return resultMap;
    }

動態代理實現代理鏈

即當一個class執行某個method方法時,要先執行一系列Proxy(接口)子類的doProxy()方法。函數

思路:this

根據isAssiginFrom獲取Proxy全部的實現類,而後根據Proxy子類上的註解獲取要攔截哪些類(切點),根據註解獲取目標類集合,生成Map<Proxy,Set<targetClass>>spa

而後轉換爲Map<targetClass,List<ProxyInstance>>,而後用代理鏈ProxyChain生成代理鏈,每當方法執行時,會先執行ProxyChain中的doProxy方法。doProxy方法執行會執行Proxy代理集合(把本身做爲參數帶進去),而後在Proxy代理實例中繼續執行ProxyChain中的doProxy方法,直到全部代理鏈執行完畢,ProxyChain執行了目標函數,而後依次返回Proxy中執行後續代碼。debug

實現步驟:代理

獲取全部的代理類code

    /**
     * 獲取應用包名下某父類(接口)的全部子類(或實現類)
     * @param superClass 父類/接口/類自己(基本數據類型)
     * @return
     */
    public static Set<Class<?>> getClassSetBySuper(Class<?> superClass){
        Set<Class<?>> classSet = new HashSet<Class<?>>();
        for (Class<?> cls:CLASS_SET){
            /*!!!!!!!!!!重點!!!!!!!!!!獲取某個基類的子類(這樣能夠獲取AOP的全部切面)*/
            if (superClass.isAssignableFrom(cls) && !superClass.equals(cls)){  //superClass是cls的父類或接口(superClass爲cls的父類/接口/自己 && superClass不等於cls)
                classSet.add(cls);
            }
        }
        return classSet;
    }

獲取全部目標類orm

    /**
     * 獲取應用包名下帶有指定註解的全部類
     * @param annotationClass 註解
     * @return
     */
    public static Set<Class<?>> getClassSetByAnnotation(Class<? extends Annotation> annotationClass){
        Set<Class<?>> classSet = new HashSet<Class<?>>();
        for (Class<?> cls : CLASS_SET){
            if (cls.isAnnotationPresent(annotationClass)){  //若是此類帶有annotationClass註解
                classSet.add(cls);
            }
        }
        return classSet;
    }

生成Map<Proxy,Set<targetClass>>對象

        /**
     * 建立全部Map<代理類,Set<代理目標類>>的映射關係
     * @return Map<代理類,Set<代理目標類>>
     * @throws Exception
     */
    private static Map<Class<?>,Set<Class<?>>> createProxyMap() throws Exception{
        Map<Class<?>,Set<Class<?>>> proxyMap = new HashMap<Class<?>, Set<Class<?>>>();   //結果集<代理類,Set<代理目標類>>
        addAspectProxy(proxyMap);   //添加普通切面
        addTransactionProxy(proxyMap);   //添加事務代理
        return proxyMap;
    }

  /**
     * 添加切面代理
     * @param proxyMap
     */
    private static void addAspectProxy(Map<Class<?>,Set<Class<?>>> proxyMap){
        //獲取全部的AspectProxy的子類(代理類集合),即切面,
        /*這個是入口,根據基類來查找全部的切面(代理類),獲取全部的切面!!!*/
        Set<Class<?>> proxyClassSet = ClassHelper.getClassSetBySuper(AspectProxy.class);
        for (Class<?> proxyClass : proxyClassSet){   //遍歷代理類(切面),如ControllerAspect
            if (proxyClass.isAnnotationPresent(Aspect.class)){    //驗證基類爲AspectProxy且要有Aspect註解的才能爲切面。若是代理類的的註解爲Aspect(也就是說代理類必定要都切點(註解)才能是切面),例如ControllerAspect代理類的註解爲@Aspect(Controller.class)
                Aspect aspect = proxyClass.getAnnotation(Aspect.class);   //獲取代理類(切面)的註解
                /*根據註解獲取全部的目標類*/
                Set<Class<?>> targetClassSet = createTargetClassSet(aspect);   //獲取全部的代理目標類集合
                proxyMap.put(proxyClass,targetClassSet);   //加入到結果集Map<代理類,Set<代理目標類>>中
            }
        }
    }

    /**
     * 根據Aspect註解(切點)獲取全部的代理目標類集合(目標類爲Controller等註解的類)
     * @param aspect 代理類註解,用來指定目標類的註解 例如:@Aspect(Controller.class)
     * @return 返回Aspect註解中指定value註解的目標類  例如:帶Controller註解的全部類
     * 例如Aspect(Controller.class)是指獲取全部Controller註解的類
     */
    private static Set<Class<?>> createTargetClassSet(Aspect aspect){
        Set<Class<?>> targetClassSet = new HashSet<Class<?>>();
        Class<? extends Annotation> annotation = aspect.value();   //獲取值(也是註解)
        if (annotation!=null && !annotation.equals(Aspect.class)){   //獲取的value註解不爲null,且註解不爲Aspect
            targetClassSet.addAll(ClassHelper.getClassSetByAnnotation(annotation));   //加入全部value(切點)指定的註解的類
        }
        return targetClassSet;   //返回全部目標類
    }

而後把Map<Proxy,Set<targetClass>>轉成Map<targetClass,List<ProxyInstance>>

    /**
     * 將Map<代理類,Set<目標類>> proxyMap轉爲Map<目標類,List<代理類>> targetMap
     * @param proxyMap Map<代理類,Set<目標類>>
     * @return Map<目標類,List<代理類實例>>
     * @throws Exception
     */
    private static Map<Class<?>,List<Proxy>> createTargetMap(Map<Class<?>,Set<Class<?>>> proxyMap) throws Exception{
        Map<Class<?>,List<Proxy>> targetMap = new HashMap<Class<?>,List<Proxy>>();   //class - list鍵值對的map
        for (Map.Entry<Class<?>,Set<Class<?>>> proxyEntry:proxyMap.entrySet()){   //遍歷cls - set鍵值對的map
            Class<?> proxyClass = proxyEntry.getKey();   //獲取代理cls
            Set<Class<?>> targetClassSet = proxyEntry.getValue();   //獲取目標Set
            for (Class<?> targetClass:targetClassSet){    //遍歷目標Set
                Proxy proxy = (Proxy) proxyClass.newInstance();   //實例化代理類
                if (targetMap.containsKey(targetClass)){    //若是Map<Class<?>,List<Proxy>>包含該目標類
                    targetMap.get(targetClass).add(proxy);   //直接將代理類添加到對應目標類的Map中
                }else{
                    List<Proxy> proxyList = new ArrayList<Proxy>();   //若是沒有
                    proxyList.add(proxy);
                    targetMap.put(targetClass,proxyList);
                }
            }
        }
        return targetMap;
    }

將Map<targetClass,List<ProxyInstance>>生成代理連

    static{
        try{
            Map<Class<?>,Set<Class<?>>> proxyMap = createProxyMap();   //獲取Map<代理類,Set<目標類>>
            Map<Class<?>,List<Proxy>> targetMap = createTargetMap(proxyMap);  //獲取Map<目標類,List<代理實例>>
            for (Map.Entry<Class<?>,List<Proxy>> targetEntry:targetMap.entrySet()){   //遍歷Map<目標類,List<代理實例>>
                Class<?> targetClass = targetEntry.getKey();   //目標類
                List<Proxy> proxyList = targetEntry.getValue();    //代理類
//生成代理鏈!!! Object proxy = ProxyManager.createProxy(targetClass,proxyList); //根據目標類和代理集合建立一個代理 BeanHelper.setBean(targetClass,proxy); //將Bean容器中目標類對應的實體替換成代理 } }catch (Exception e){ LOGGER.error("aop failure",e); } }

代理鏈實現以下:

Proxy接口及其實現,這裏用到模板方法模式

/**
 * 代理接口
 */
public interface Proxy {

    /**
     * 執行鏈式代理
     * @param proxyChain 這個鏈式代理參數中含有全部的代理類,和目標類的參數(類、方法、方法參數)
     * @return
     * @throws Throwable
     */
    Object doProxy(ProxyChain proxyChain) throws Throwable;
}

/**
 * 切面代理
 */
public abstract class AspectProxy implements Proxy{
    private static final Logger logger = LoggerFactory.getLogger(AspectProxy.class);

    /**
     * 執行鏈式代理
     */
    @Override
    public Object doProxy(ProxyChain proxyChain) throws Throwable {
        Object result = null;
        //獲取目標類、方法、方法參數
        Class<?> cls = proxyChain.getTargetClass();
        Method method = proxyChain.getTargetMethod();
        Object[] params = proxyChain.getMethodParams();

        begin();    //代理開始時執行begin方法
        try {
            if (intercept(cls,method,params)){    //判斷是否攔截此方法
                before(cls,method,params);     //目標方法執行前代理方法before執行
                result = proxyChain.doProxyChain();   //執行下一個代理
                after(cls,method,result);    //目標方法執行後代理方法after執行
            }else {
                result = proxyChain.doProxyChain();    //執行下一個代理
            }
        }catch(Exception e){
            logger.error("proxy failure",e);
            error(cls,method,params,e);    //拋出異常時代理方法error執行
            throw e;
        }finally{
            end();    //代理結束時執行方法end
        }
        return result;
    }
    /*方法開始前執行*/
    public void begin(){
    }

    /**
     * 攔截
     * @param cls 目標類
     * @param method 目標方法
     * @param params 目標方法參數
     * @return 返回是否攔截
     */
    public boolean intercept(Class<?> cls, Method method, Object[] params) throws Throwable {
        return true;
    }

    /**
     * 前置加強
     * @param cls 目標類
     * @param method 目標方法
     * @param params 目標方法參數
     */
    public void before(Class<?> cls, Method method, Object[] params) throws Throwable {
    }
    /**
     * 後置加強
     * @param cls 目標類
     * @param method 目標方法
     * @param result 目標方法返回結果
     */
    public void after(Class<?> cls, Method method, Object result) throws Throwable {
    }

    /**
     * 拋出加強
     * @param cls 目標類
     * @param method 目標方法
     * @param params 目標方法參數
     * @param e 異常
     * @throws Throwable
     */
    public void error(Class<?> cls, Method method, Object[] params, Exception e) throws Throwable {
    }
    /*方法結束後執行*/
    public void end(){
    }
}

/**
 * 攔截全部Controller方法
 * 這個切面寫在框架裏用不了,由於不會加載這個類到CLASS_SET
 */
@Aspect(Controller.class)
public class ControllerAspect extends AspectProxy{
    private static final Logger LOGGER = LoggerFactory.getLogger(ControllerAspect.class);
    private long begin;    //方法開始時間

    /**
     * 前置加強
     * @param cls    目標類
     * @param method 目標方法
     * @param params 目標方法參數
     */
    @Override
    public void before(Class<?> cls, Method method, Object[] params) throws Throwable {
        LOGGER.debug("---------begin---------");
        LOGGER.debug(String.format("class: %s",cls.getName()));
        LOGGER.debug(String.format("method: %s",method.getName()));
        begin = System.currentTimeMillis();
    }

    /**
     * 後置加強
     * @param cls    目標類
     * @param method 目標方法
     * @param result 目標方法返回結果
     */
    @Override
    public void after(Class<?> cls, Method method, Object result) throws Throwable {
        LOGGER.debug(String.format("time: %ds", System.currentTimeMillis()-begin));
        LOGGER.debug("---------end---------");
    }
}

用到的註解

/**
 * 切面註解
 * 用來指定切點爲哪些註解
 * Controller這類註解
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Aspect {
    /*值爲註解,也就是說切點爲指定的註解 -  值爲Controller或者Service等註解*/
    Class<? extends Annotation> value();
}

代理鏈類

/**
 * 代理鏈
 */
public class ProxyChain {
    private final Class<?> targetClass;    //代理類
    private final Object targetObject;    //目標對象
    private final Method targetMethod;    //目標方法
    private final MethodProxy methodProxy;    //代理方法 - CGLib中參數
    private final Object[] methodParams;    //方法參數

    private List<Proxy> proxyList = new ArrayList<Proxy>();   //代理列表 - 各類代理類 例如ControllerAspect等類
    private int proxyIndex = 0;    //代理索引

    public ProxyChain(Class<?> targetClass, Object targetObject, Method targetMethod, MethodProxy methodProxy, Object[] methodParams, List<Proxy> proxyList) {
        this.targetClass = targetClass;
        this.targetObject = targetObject;
        this.targetMethod = targetMethod;
        this.methodProxy = methodProxy;
        this.methodParams = methodParams;
        this.proxyList = proxyList;
    }

    public Class<?> getTargetClass() {
        return targetClass;
    }

    public Method getTargetMethod() {
        return targetMethod;
    }

    public Object[] getMethodParams() {
        return methodParams;
    }

    /**
     * 調用代理類及目標類
     * 這個比較有意思,經過代理鏈的實例proxyChain不斷調用此方法,每次調用都會拿出list中的一個代理執行doProxy方法(doProxy方法中再用proxyChain實例調用此方法)
     * @return 返回目標類執行的結果
     * @throws Throwable
     */
    public Object doProxyChain() throws Throwable {
        Object methodResult;
        if (proxyIndex<proxyList.size()){   //若是代理索引小於代理列表大小
            //從列表中取出Proxy對象,調用器doProxy方法
            methodResult = proxyList.get(proxyIndex++).doProxy(this);
        }else {    //全部代理遍歷完後
            methodResult = methodProxy.invokeSuper(targetObject,methodParams);  //執行目標對象業務
        }
        return methodResult;
    }
}

代理鏈管理器(生成代理鏈)

/**
 * 代理管理器
 */
public class ProxyManager {
    /**
     * 根據目標類和代理列表建立一個代理鏈
     * @param targetClass  目標類
     * @param proxyList  代理列表
     * @param <T> 返回一個代理鏈執行的返回結果
     * @return
     */
    public static <T> T createProxy(final Class<T> targetClass, final List<Proxy> proxyList){
        return (T) Enhancer.create(targetClass, new MethodInterceptor() {   //方法執行時纔會執行此代碼塊
            @Override
            public Object intercept(Object targetObject, Method targetMethod, Object[] methodParams, MethodProxy methodProxy) throws Throwable {
                //每一個方法執行都會執行性代理鏈的doProxyChain方法(這裏每執行一個目標類的方法,都會new一個代理鏈並執行該代理鏈)
                return new ProxyChain(targetClass,targetObject,targetMethod,methodProxy,methodParams,proxyList).doProxyChain();
            }
        });
    }
}

這裏Proxy用到了模板方法模式,代理鏈生成及運行時CGLib起做用的精華。每運行一個方法,都會去調用代理鏈的doProxy方法,而代理鏈的doProxy方法中又會根據代理類集合的下標依次調用doProxy方法。

Java對象轉Json 

目標Json

var data = [
            ['2016/12/18 6:38:08', 80],
            ['2016/12/18 16:18:18', 60],
            ['2016/12/18 19:18:18', 90]
           ];

Java實現

List<Object[]> data = new LinkedList<Object[]>();
//若是須要多個這樣的數據
Map<String, List> resultMap = new HashedMap();
resultMap.put("data", data);
Gson gson = new Gson();
String result = gson.toJson(data);
相關文章
相關標籤/搜索