本人微信公众号"aeolian"~

JAVA常用编程代码块

转Map时要考虑Map的key是否重复

List转为Map

将一个List实体集合转换为以Entity某一个字段为key,另一字段为value映射的Map

    /**
     * List转换为Map
     */
    public Map getMapByList(List list){
        Map resultMap= new HashMap();  //结果,字段/值的映射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转为Map>

将List中的实体根据keyField字段分类成Map

     public Map> getMapByList(List list){
        Map> resultMap = new HashMap>();   //目标结果Map

        if (CollectionUtil.isNotEmpty(list)){    //判断是否为空
            for (Entity entity:list){    //遍历List集合
                String keyField = entity.getKeyField();    //获取key字段值
              
                /****************************考虑Map中key值重复的情况*****************************/
                List list;   //根据keyField分组的list
                if (resultMap.containsKey(keyField)){    //如果之前有keyField字段对一个的实体已经放入过List,即已经存在在结果Map中
                    list = resultMap.get(keyField);   //根据keyFiedl获取Map中对应的List集合
                }else{
                    list = new ArrayList();  //这个字段之前没有放入过实体,没有List,新建一个List
                }
                list.add(entity);   //放入到keyField对应的List中去
                /*************************考虑Map中key值重复的情况结束********************************/
                
                resultMap.put(keyField,list);   //放入到Map>的映射中
            }
        }
        return resultMap;
    }

动态代理实现代理链

即当一个class执行某个method方法时,要先执行一系列Proxy(接口)子类的doProxy()方法。

思路:

根据isAssiginFrom获取Proxy所有的实现类,然后根据Proxy子类上的注解获取要拦截哪些类(切点),根据注解获取目标类集合,生成Map>

然后转换为Map>,然后用代理链ProxyChain生成代理链,每当方法执行时,会先执行ProxyChain中的doProxy方法。doProxy方法执行会执行Proxy代理集合(把自己作为参数带进去),然后在Proxy代理实例中继续执行ProxyChain中的doProxy方法,直到所有代理链执行完毕,ProxyChain执行了目标函数,然后依次返回Proxy中执行后续代码。

实现步骤:

获取所有的代理类

    /**
     * 获取应用包名下某父类(接口)的所有子类(或实现类)
     * @param superClass 父类/接口/类本身(基本数据类型)
     * @return
     */
    public static Set> getClassSetBySuper(Class superClass){
        Set> classSet = new HashSet>();
        for (Class cls:CLASS_SET){
            /*!!!!!!!!!!重点!!!!!!!!!!获取某个基类的子类(这样可以获取AOP的所有切面)*/
            if (superClass.isAssignableFrom(cls) && !superClass.equals(cls)){  //superClass是cls的父类或接口(superClass为cls的父类/接口/本身 && superClass不等于cls)
                classSet.add(cls);
            }
        }
        return classSet;
    }

获取所有目标类

    /**
     * 获取应用包名下带有指定注解的所有类
     * @param annotationClass 注解
     * @return
     */
    public static Set> getClassSetByAnnotation(Classextends Annotation> annotationClass){
        Set> classSet = new HashSet>();
        for (Class cls : CLASS_SET){
            if (cls.isAnnotationPresent(annotationClass)){  //如果此类带有annotationClass注解
                classSet.add(cls);
            }
        }
        return classSet;
    }

生成Map>

        /**
     * 创建所有Map<代理类,Set<代理目标类>>的映射关系
     * @return Map<代理类,Set<代理目标类>>
     * @throws Exception
     */
    private static Map,Set>> createProxyMap() throws Exception{
        Map,Set>> proxyMap = new HashMap, Set>>();   //结果集<代理类,Set<代理目标类>>
        addAspectProxy(proxyMap);   //添加普通切面
        addTransactionProxy(proxyMap);   //添加事务代理
        return proxyMap;
    }

  /**
     * 添加切面代理
     * @param proxyMap
     */
    private static void addAspectProxy(Map,Set>> proxyMap){
        //获取所有的AspectProxy的子类(代理类集合),即切面,
        /*这个是入口,根据基类来查找所有的切面(代理类),获取所有的切面!!!*/
        Set> 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> 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> createTargetClassSet(Aspect aspect){
        Set> targetClassSet = new HashSet>();
        Classextends Annotation> annotation = aspect.value();   //获取值(也是注解)
        if (annotation!=null && !annotation.equals(Aspect.class)){   //获取的value注解不为null,且注解不为Aspect
            targetClassSet.addAll(ClassHelper.getClassSetByAnnotation(annotation));   //加入所有value(切点)指定的注解的类
        }
        return targetClassSet;   //返回所有目标类
    }

然后把Map>转成Map>

    /**
     * 将Map<代理类,Set<目标类>> proxyMap转为Map<目标类,List<代理类>> targetMap
     * @param proxyMap Map<代理类,Set<目标类>>
     * @return Map<目标类,List<代理类实例>>
     * @throws Exception
     */
    private static Map,List> createTargetMap(Map,Set>> proxyMap) throws Exception{
        Map,List> targetMap = new HashMap,List>();   //class - list键值对的map
        for (Map.Entry,Set>> proxyEntry:proxyMap.entrySet()){   //遍历cls - set键值对的map
            Class proxyClass = proxyEntry.getKey();   //获取代理cls
            Set> targetClassSet = proxyEntry.getValue();   //获取目标Set
            for (Class targetClass:targetClassSet){    //遍历目标Set
                Proxy proxy = (Proxy) proxyClass.newInstance();   //实例化代理类
                if (targetMap.containsKey(targetClass)){    //如果Map,List>包含该目标类
                    targetMap.get(targetClass).add(proxy);   //直接将代理类添加到对应目标类的Map中
                }else{
                    List proxyList = new ArrayList();   //如果没有
                    proxyList.add(proxy);
                    targetMap.put(targetClass,proxyList);
                }
            }
        }
        return targetMap;
    }

将Map>生成代理连

    static{
        try{
            Map,Set>> proxyMap = createProxyMap();   //获取Map<代理类,Set<目标类>>
            Map,List> targetMap = createTargetMap(proxyMap);  //获取Map<目标类,List<代理实例>>
            for (Map.Entry,List> targetEntry:targetMap.entrySet()){   //遍历Map<目标类,List<代理实例>>
                Class targetClass = targetEntry.getKey();   //目标类
                List 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等注解*/
    Classextends 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 proxyList = new ArrayList();   //代理列表 - 各种代理类 例如ControllerAspect等类
    private int proxyIndex = 0;    //代理索引

    public ProxyChain(Class targetClass, Object targetObject, Method targetMethod, MethodProxy methodProxy, Object[] methodParams, List 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//如果代理索引小于代理列表大小
            //从列表中取出Proxy对象,调用器doProxy方法
            methodResult = proxyList.get(proxyIndex++).doProxy(this);
        }else {    //所有代理遍历完后
            methodResult = methodProxy.invokeSuper(targetObject,methodParams);  //执行目标对象业务
        }
        return methodResult;
    }
}

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

/**
 * 代理管理器
 */
public class ProxyManager {
    /**
     * 根据目标类和代理列表创建一个代理链
     * @param targetClass  目标类
     * @param proxyList  代理列表
     * @param  返回一个代理链执行的返回结果
     * @return
     */
    public static  T createProxy(final Class targetClass, final List 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 data = new LinkedList();
//如果需要多个这样的数据
Map resultMap = new HashedMap();
resultMap.put("data", data);
Gson gson = new Gson();
String result = gson.toJson(data);

 

点赞

Leave a Reply

Your email address will not be published. Required fields are marked *