转Map时要考虑Map的key是否重复
List<Entity>转为Map<keyField, valueField>
将一个List实体集合转换为以Entity某一个字段为key,另一字段为value映射的Map
1/** 2 * List转换为Map<key字段,val字段/实体> 3 */ 4 public Map<String,Object> getMapByList(List list){ 5 Map<String,Object> resultMap= new HashMap<String,Object>(); //结果,字段/值的映射map 6 7 if (CollectionUtil.isNotEmpty(list)){ //先判断list是否为空 8 for (Entity entity:list){ //遍历List 9 String keyField= entity.getKeyField(); //键 10 Object valueField = entity.getValField(); //值,值也可以为其他字段或者整个对象 11 /********遍历list的key字段不能直接放入Map中,因为可能有重复的,这样发现不了问题*********/ 12 if (resultMap.containsKey(keyField)){ //如果key字段的值是有重复的 13 valueField = resultMap.get(keyField) + StringUtil.SEPARATOR + valueField; //value字段的值为: 旧的数据<-->新的数据作为value 14 } /**********处理可能重复key的情况结束************/ 15 resultMap.put(keyField,valueField); //最后在将处理后的keyField和valueField放入到Map中去 16 } 17 } 18 return resultMap; 19 }
List<Entity>转为Map<keyField,List<Entity>>
将List中的实体根据keyField字段分类成Map<keyField,List>
1public Map<String,List<Entity>> getMapByList(List<Entity> list){ 2 Map<String,List<Entity>> resultMap = new HashMap<String,List<Entity>>(); //目标结果Map 3 4 if (CollectionUtil.isNotEmpty(list)){ //判断是否为空 5 for (Entity entity:list){ //遍历List集合 6 String keyField = entity.getKeyField(); //获取key字段值 7 8 /****************************考虑Map中key值重复的情况*****************************/ 9 List<Entity> list; //根据keyField分组的list 10 if (resultMap.containsKey(keyField)){ //如果之前有keyField字段对一个的实体已经放入过List,即已经存在在结果Map中 11 list = resultMap.get(keyField); //根据keyFiedl获取Map中对应的List集合 12 }else{ 13 list = new ArrayList<Entity>(); //这个字段之前没有放入过实体,没有List,新建一个List 14 } 15 list.add(entity); //放入到keyField对应的List中去 16 /*************************考虑Map中key值重复的情况结束********************************/ 17 18 resultMap.put(keyField,list); //放入到Map<keyField,List<Entity>>的映射中 19 } 20 } 21 return resultMap; 22 }
动态代理实现代理链
即当一个class执行某个method方法时,要先执行一系列Proxy(接口)子类的doProxy()方法。
思路:
根据isAssiginFrom获取Proxy所有的实现类,然后根据Proxy子类上的注解获取要拦截哪些类(切点),根据注解获取目标类集合,生成Map<Proxy,Set<targetClass>>
然后转换为Map<targetClass,List<ProxyInstance>>,然后用代理链ProxyChain生成代理链,每当方法执行时,会先执行ProxyChain中的doProxy方法。doProxy方法执行会执行Proxy代理集合(把自己作为参数带进去),然后在Proxy代理实例中继续执行ProxyChain中的doProxy方法,直到所有代理链执行完毕,ProxyChain执行了目标函数,然后依次返回Proxy中执行后续代码。
实现步骤:
获取所有的代理类
1/** 2 * 获取应用包名下某父类(接口)的所有子类(或实现类) 3 * @param superClass 父类/接口/类本身(基本数据类型) 4 * @return 5 */ 6 public static Set<Class<?>> getClassSetBySuper(Class<?> superClass){ 7 Set<Class<?>> classSet = new HashSet<Class<?>>(); 8 for (Class<?> cls:CLASS_SET){ 9 /*!!!!!!!!!!重点!!!!!!!!!!获取某个基类的子类(这样可以获取AOP的所有切面)*/ 10 if (superClass.isAssignableFrom(cls) && !superClass.equals(cls)){ //superClass是cls的父类或接口(superClass为cls的父类/接口/本身 && superClass不等于cls) 11 classSet.add(cls); 12 } 13 } 14 return classSet; 15 }
获取所有目标类
1/** 2 * 获取应用包名下带有指定注解的所有类 3 * @param annotationClass 注解 4 * @return 5 */ 6 public static Set<Class<?>> getClassSetByAnnotation(Class<? extends Annotation> annotationClass){ 7 Set<Class<?>> classSet = new HashSet<Class<?>>(); 8 for (Class<?> cls : CLASS_SET){ 9 if (cls.isAnnotationPresent(annotationClass)){ //如果此类带有annotationClass注解 10 classSet.add(cls); 11 } 12 } 13 return classSet; 14 }
生成Map<Proxy,Set<targetClass>>
1/** 2 * 创建所有Map<代理类,Set<代理目标类>>的映射关系 3 * @return Map<代理类,Set<代理目标类>> 4 * @throws Exception 5 */ 6 private static Map<Class<?>,Set<Class<?>>> createProxyMap() throws Exception{ 7 Map<Class<?>,Set<Class<?>>> proxyMap = new HashMap<Class<?>, Set<Class<?>>>(); //结果集<代理类,Set<代理目标类>> 8 addAspectProxy(proxyMap); //添加普通切面 9 addTransactionProxy(proxyMap); //添加事务代理 10 return proxyMap; 11 } 12 13 /** 14 * 添加切面代理 15 * @param proxyMap 16 */ 17 private static void addAspectProxy(Map<Class<?>,Set<Class<?>>> proxyMap){ 18 //获取所有的AspectProxy的子类(代理类集合),即切面, 19 /*这个是入口,根据基类来查找所有的切面(代理类),获取所有的切面!!!*/ 20 Set<Class<?>> proxyClassSet = ClassHelper.getClassSetBySuper(AspectProxy.class); 21 for (Class<?> proxyClass : proxyClassSet){ //遍历代理类(切面),如ControllerAspect 22 if (proxyClass.isAnnotationPresent(Aspect.class)){ //验证基类为AspectProxy且要有Aspect注解的才能为切面。如果代理类的的注解为Aspect(也就是说代理类一定要都切点(注解)才能是切面),例如ControllerAspect代理类的注解为@Aspect(Controller.class) 23 Aspect aspect = proxyClass.getAnnotation(Aspect.class); //获取代理类(切面)的注解 24 /*根据注解获取所有的目标类*/ 25 Set<Class<?>> targetClassSet = createTargetClassSet(aspect); //获取所有的代理目标类集合 26 proxyMap.put(proxyClass,targetClassSet); //加入到结果集Map<代理类,Set<代理目标类>>中 27 } 28 } 29 } 30 31 /** 32 * 根据Aspect注解(切点)获取所有的代理目标类集合(目标类为Controller等注解的类) 33 * @param aspect 代理类注解,用来指定目标类的注解 例如:@Aspect(Controller.class) 34 * @return 返回Aspect注解中指定value注解的目标类 例如:带Controller注解的所有类 35 * 例如Aspect(Controller.class)是指获取所有Controller注解的类 36 */ 37 private static Set<Class<?>> createTargetClassSet(Aspect aspect){ 38 Set<Class<?>> targetClassSet = new HashSet<Class<?>>(); 39 Class<? extends Annotation> annotation = aspect.value(); //获取值(也是注解) 40 41if (annotation!=null && !annotation.equals(Aspect.class)){ //获取的value注解不为null,且注解不为Aspect 42 targetClassSet.addAll(ClassHelper.getClassSetByAnnotation(annotation)); //加入所有value(切点)指定的注解的类 43 } 44 return targetClassSet; //返回所有目标类 45 }
然后把Map<Proxy,Set<targetClass>>转成Map<targetClass,List<ProxyInstance>>
1/** 2 * 将Map<代理类,Set<目标类>> proxyMap转为Map<目标类,List<代理类>> targetMap 3 * @param proxyMap Map<代理类,Set<目标类>> 4 * @return Map<目标类,List<代理类实例>> 5 * @throws Exception 6 */ 7 private static Map<Class<?>,List<Proxy>> createTargetMap(Map<Class<?>,Set<Class<?>>> proxyMap) throws Exception{ 8 Map<Class<?>,List<Proxy>> targetMap = new HashMap<Class<?>,List<Proxy>>(); //class - list键值对的map 9 for (Map.Entry<Class<?>,Set<Class<?>>> proxyEntry:proxyMap.entrySet()){ //遍历cls - set键值对的map 10 Class<?> proxyClass = proxyEntry.getKey(); //获取代理cls 11 Set<Class<?>> targetClassSet = proxyEntry.getValue(); //获取目标Set 12 for (Class<?> targetClass:targetClassSet){ //遍历目标Set 13 Proxy proxy = (Proxy) proxyClass.newInstance(); //实例化代理类 14 if (targetMap.containsKey(targetClass)){ //如果Map<Class<?>,List<Proxy>>包含该目标类 15 targetMap.get(targetClass).add(proxy); //直接将代理类添加到对应目标类的Map中 16 }else{ 17 List<Proxy> proxyList = new ArrayList<Proxy>(); //如果没有 18 proxyList.add(proxy); 19 targetMap.put(targetClass,proxyList); 20 } 21 } 22 } 23 return targetMap; 24 }
将Map<targetClass,List<ProxyInstance>>生成代理连
1static{ 2 try{ 3 Map<Class<?>,Set<Class<?>>> proxyMap = createProxyMap(); //获取Map<代理类,Set<目标类>> 4 Map<Class<?>,List<Proxy>> targetMap = createTargetMap(proxyMap); //获取Map<目标类,List<代理实例>> 5 for (Map.Entry<Class<?>,List<Proxy>> targetEntry:targetMap.entrySet()){ //遍历Map<目标类,List<代理实例>> 6 Class<?> targetClass = targetEntry.getKey(); //目标类 7 List<Proxy> proxyList = targetEntry.getValue(); //代理类 //生成代理链!!! 8 Object proxy = ProxyManager.createProxy(targetClass,proxyList); //根据目标类和代理集合创建一个代理 9 BeanHelper.setBean(targetClass,proxy); //将Bean容器中目标类对应的实体替换成代理 10 } 11 }catch (Exception e){ 12 LOGGER.error("aop failure",e); 13 } 14 }
代理链实现如下:
Proxy接口及其实现,这里用到模板方法模式
1/** 2 * 代理接口 3 */ 4public interface Proxy { 5 6 /** 7 * 执行链式代理 8 * @param proxyChain 这个链式代理参数中含有所有的代理类,和目标类的参数(类、方法、方法参数) 9 * @return 10 * @throws Throwable 11 */ 12 Object doProxy(ProxyChain proxyChain) throws Throwable; 13} 14 15/** 16 * 切面代理 17 */ 18public abstract class AspectProxy implements Proxy{ 19 private static final Logger logger = LoggerFactory.getLogger(AspectProxy.class); 20 21 /** 22 * 执行链式代理 23 */ 24 @Override 25 public Object doProxy(ProxyChain proxyChain) throws Throwable { 26 Object result = null; 27 //获取目标类、方法、方法参数 28 Class<?> cls = proxyChain.getTargetClass(); 29 Method method = proxyChain.getTargetMethod(); 30 Object[] params = proxyChain.getMethodParams(); 31 32 begin(); //代理开始时执行begin方法 33 try { 34 if (intercept(cls,method,params)){ //判断是否拦截此方法 35 before(cls,method,params); //目标方法执行前代理方法before执行 36 result = proxyChain.doProxyChain(); //执行下一个代理 37 after(cls,method,result); //目标方法执行后代理方法after执行 38 }else { 39 result = proxyChain.doProxyChain(); //执行下一个代理 40 } 41 }catch(Exception e){ 42 logger.error("proxy failure",e); 43 error(cls,method,params,e); //抛出异常时代理方法error执行 44 throw e; 45 }finally{ 46 end(); //代理结束时执行方法end 47 } 48 return result; 49 } 50 /*方法开始前执行*/ 51 public void begin(){ 52 } 53 54 /** 55 * 拦截 56 * @param cls 目标类 57 * @param method 目标方法 58 * @param params 目标方法参数 59 * @return 返回是否拦截 60 */ 61 public boolean intercept(Class<?> cls, Method method, Object[] params) throws Throwable { 62 return true; 63 } 64 65 /** 66 * 前置增强 67 * @param cls 目标类 68 * @param method 目标方法 69 * @param params 目标方法参数 70 */ 71 public void before(Class<?> cls, Method method, Object[] params) throws Throwable { 72 } 73 /** 74 * 后置增强 75 * @param cls 目标类 76 * @param method 目标方法 77 * @param result 目标方法返回结果 78 */ 79 public void after(Class<?> cls, Method method, Object result) throws Throwable { 80 } 81 82 /** 83 * 抛出增强 84 * @param cls 目标类 85 * @param method 目标方法 86 * @param params 目标方法参数 87 * @param e 异常 88 * @throws Throwable 89 */ 90 public void error(Class<?> cls, Method method, Object[] params, Exception e) throws Throwable { 91 } 92 /*方法结束后执行*/ 93 public void end(){ 94 } 95} 96 97/** 98 * 拦截所有Controller方法 99 * 这个切面写在框架里用不了,因为不会加载这个类到CLASS_SET 100 */ 101@Aspect(Controller.class) 102public class ControllerAspect extends AspectProxy{ 103 private static final Logger LOGGER = LoggerFactory.getLogger(ControllerAspect.class); 104 private long begin; //方法开始时间 105 106 /** 107 * 前置增强 108 * @param cls 目标类 109 * @param method 目标方法 110 * @param params 目标方法参数 111 */ 112 @Override 113 public void before(Class<?> cls, Method method, Object[] params) throws Throwable { 114 LOGGER.debug("---------begin---------"); 115 LOGGER.debug(String.format("class: %s",cls.getName())); 116 LOGGER.debug(String.format("method: %s",method.getName())); 117 begin = System.currentTimeMillis(); 118 } 119 120 /** 121 * 后置增强 122 * @param cls 目标类 123 * @param method 目标方法 124 * @param result 目标方法返回结果 125 */ 126 @Override 127 public void after(Class<?> cls, Method method, Object result) throws Throwable { 128 LOGGER.debug(String.format("time: %ds", System.currentTimeMillis()-begin)); 129 LOGGER.debug("---------end---------"); 130 } 131}
用到的注解
1/** 2 * 切面注解 3 * 用来指定切点为哪些注解 4 * Controller这类注解 5 */ 6@Target(ElementType.TYPE) 7@Retention(RetentionPolicy.RUNTIME) 8public @interface Aspect { 9 /*值为注解,也就是说切点为指定的注解 - 值为Controller或者Service等注解*/ 10 Class<? extends Annotation> value(); 11}
代理链类
1/** 2 * 代理链 3 */ 4public class ProxyChain { 5 private final Class<?> targetClass; //代理类 6 private final Object targetObject; //目标对象 7 private final Method targetMethod; //目标方法 8 private final MethodProxy methodProxy; //代理方法 - CGLib中参数 9 private final Object[] methodParams; //方法参数 10 11 private List<Proxy> proxyList = new ArrayList<Proxy>(); //代理列表 - 各种代理类 例如ControllerAspect等类 12 private int proxyIndex = 0; //代理索引 13 14 public ProxyChain(Class<?> targetClass, Object targetObject, Method targetMethod, MethodProxy methodProxy, Object[] methodParams, List<Proxy> proxyList) { 15 this.targetClass = targetClass; 16 this.targetObject = targetObject; 17 this.targetMethod = targetMethod; 18 this.methodProxy = methodProxy; 19 this.methodParams = methodParams; 20 this.proxyList = proxyList; 21 } 22 23 public Class<?> getTargetClass() { 24 return targetClass; 25 } 26 27 public Method getTargetMethod() { 28 return targetMethod; 29 } 30 31 public Object[] getMethodParams() { 32 return methodParams; 33 } 34 35 /** 36 * 调用代理类及目标类 37 * 这个比较有意思,通过代理链的实例proxyChain不断调用此方法,每次调用都会拿出list中的一个代理执行doProxy方法(doProxy方法中再用proxyChain实例调用此方法) 38 * @return 返回目标类执行的结果 39 * @throws Throwable 40 */ 41 public Object doProxyChain() throws Throwable { 42 Object methodResult; 43 if (proxyIndex<proxyList.size()){ //如果代理索引小于代理列表大小 44 //从列表中取出Proxy对象,调用器doProxy方法 45 methodResult = proxyList.get(proxyIndex++).doProxy(this); 46 }else { //所有代理遍历完后 47 methodResult = methodProxy.invokeSuper(targetObject,methodParams); //执行目标对象业务 48 } 49 return methodResult; 50 } 51}
代理链管理器(生成代理链)
1/** 2 * 代理管理器 3 */ 4public class ProxyManager { 5 /** 6 * 根据目标类和代理列表创建一个代理链 7 * @param targetClass 目标类 8 * @param proxyList 代理列表 9 * @param <T> 返回一个代理链执行的返回结果 10 * @return 11 */ 12 public static <T> T createProxy(final Class<T> targetClass, final List<Proxy> proxyList){ 13 return (T) Enhancer.create(targetClass, new MethodInterceptor() { //方法执行时才会执行此代码块 14 @Override 15 public Object intercept(Object targetObject, Method targetMethod, Object[] methodParams, MethodProxy methodProxy) throws Throwable { 16 //每个方法执行都会执行性代理链的doProxyChain方法(这里每执行一个目标类的方法,都会new一个代理链并执行该代理链) 17 return new ProxyChain(targetClass,targetObject,targetMethod,methodProxy,methodParams,proxyList).doProxyChain(); 18 } 19 }); 20 } 21}
这里Proxy用到了模板方法模式,代理链生成及运行时CGLib起作用的精华。每运行一个方法,都会去调用代理链的doProxy方法,而代理链的doProxy方法中又会根据代理类集合的下标依次调用doProxy方法。
Java对象转Json
目标Json
1var data = [ 2 ['2016/12/18 6:38:08', 80], 3 ['2016/12/18 16:18:18', 60], 4 ['2016/12/18 19:18:18', 90] 5 ];
Java实现
1List<Object[]> data = new LinkedList<Object[]>(); 2//如果需要多个这样的数据 3Map<String, List> resultMap = new HashedMap(); 4resultMap.put("data", data); 5Gson gson = new Gson(); 6String result = gson.toJson(data);