转Map时要考虑Map的key是否重复
List<Entity>转为Map<keyField, valueField>
将一个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<Entity>转为Map<keyField,List<Entity>>
将List中的实体根据keyField字段分类成Map<keyField,List>
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<Proxy,Set<targetClass>>
然后转换为Map<targetClass,List<ProxyInstance>>,然后用代理链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(Class annotationClass){ Set > classSet = new HashSet >(); 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,Set 代理目标类> 代理类,set> 代理目标类> 代理类,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 代理目标类> 代理类,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 代理目标类> 代理类,set>> targetClassSet = new HashSet >(); Class 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,List 代理类实例> 目标类,list> 目标类> 代理类,set> 代理类> 目标类,list> 目标类> 代理类,set>> 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<targetClass,List<ProxyInstance>>生成代理连
static{ try{ Map,Set >> proxyMap = createProxyMap(); //获取Map <代理类,set> <目标类> > Map ,List 目标类> 代理类,set>> targetMap = createTargetMap(proxyMap); //获取Map <目标类,list> <代理实例> > for (Map.Entry ,List 代理实例> 目标类,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); } } 代理实例> 目标类,list>
代理链实现如下:
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 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 ListproxyList = 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
代理链管理器(生成代理链)
/** * 代理管理器 */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