美文网首页
使用反射实现遍历bean的属性

使用反射实现遍历bean的属性

作者: sliverTwo | 来源:发表于2020-03-29 20:18 被阅读0次

    在某些情况下,我们需要对bean的属性进行遍历处理,使用getXXX方法未免过于繁琐,特别是对属性处理的相同时,如:动态拼接SQL。基于此需求,本人采用反射机制对遍历bean做了一个简单的实现。

    实现思路

    关于实现bean属性的遍历主要有三种方式

    1. 调用getXXX方法。
    2. 将其转换为序列化JSON再转成Map或者JsonObject对象.
    3. 使用反射机制获取getXXX方法,进行遍历。以下实现使用了第三种方式(可以使用Hutool中的BeanUtil.beanToMap实现)

    具体实现

       /**
        * <p>Title: BeanPropCache.java</p>
        * <p>Description: </p>
        * <p>Copyright: Copyright (c) 2020</p>
        * <p>Company: www.iipcloud.com</p>
        * 
        * @author sliver
        * @date 2020年3月29日
        * @version 1.0
        */
       package com.iipcloud.base;
       
       import java.lang.reflect.Method;
       import java.util.ArrayList;
       import java.util.List;
       import java.util.concurrent.ExecutionException;
       
       import com.google.common.cache.Cache;
       import com.google.common.cache.CacheBuilder;
       
       /**
        * Title: BeanPropCache
        * Description:
        * 
        * @author sliver
        * @date 2020年3月29日
        */
       enum BeanPropCache {
           ME;
           private final Cache<Class<? extends IForeachAbleBean>, List<BeanProp>> cache;
       
           BeanPropCache() {
               cache = CacheBuilder.newBuilder().build();
           }
       
           public List<BeanProp> getBeanProp(Class<? extends IForeachAbleBean> beanClass) {
               try {
                   return cache.get(beanClass, () -> {
                       Method[] methods = beanClass.getDeclaredMethods();
                       List<BeanProp> beanProps = new ArrayList<>(methods.length);
                       for (Method method : methods) {
                           String methodName = method.getName();
                           boolean isGetMethod = methodName.startsWith("get") && method.getParameterCount() == 0;
                           if (isGetMethod) {
                               BeanProp prop = BeanProp.of(method);
                               beanProps.add(prop);
       
                           }
                       }
                       return beanProps;
                   });
               } catch (ExecutionException e) {
                   throw new RuntimeException(e);
               }
           }
       
       }
    
        
     /**
      * <p>Title: BeanProp.java</p>
      * <p>Description: </p>
      * <p>Copyright: Copyright (c) 2020</p>
      * <p>Company: www.iipcloud.com</p>
      * 
      * @author sliver
      * @date 2020年3月29日
      * @version 1.0
      */
     package com.iipcloud.base;
     
     import java.lang.reflect.InvocationTargetException;
     import java.lang.reflect.Method;
     import java.lang.reflect.Type;
     
     import com.jfinal.kit.StrKit;
     
     /**
      * Title: BeanProp
      * Description: bean类中的属性
      * 
      * @author sliver
      * @date 2020年3月29日
      * @since JDK1.8
      */
     public class BeanProp {
         /** name 属性名称 */
         private final String name;
         /** value 属性值 */
         private final Object value;
         /** type 属性类型 */
         private final Type type;
         private final Method getter;
     
         static BeanProp of(BeanProp prop) {
             return new BeanProp(prop.getName(), null, prop.getType(), prop.getGetter());
         }
     
         static BeanProp of(BeanProp prop, IForeachAbleBean object) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
             Object value = prop.getGetter().invoke(object);
             return new BeanProp(prop.getName(), value, prop.getType(), prop.getGetter());
         }
     
         static BeanProp of(Method getter) {
             String methodName = getter.getName();
             boolean isGetMethod = methodName.startsWith("get") && getter.getParameterCount() == 0;
             if (!isGetMethod) {
                 throw new IllegalArgumentException("only accept getXXX method");
             }
             String name = StrKit.firstCharToLowerCase(methodName.substring(3));
             return new BeanProp(name, null, getter.getReturnType(), getter);
         }
     
         BeanProp(String name, Object value, Type type, Method getter) {
             super();
             this.name = name;
             this.value = value;
             this.type = type;
             this.getter = getter;
         }
     
         public String getName() {
             return name;
         }
     
         public Object getValue() {
             return value;
         }
     
         public Type getType() {
             return type;
         }
     
         public Method getGetter() {
             return getter;
         }
     
     }
    
    /**
     * <p>Title: IBean.java</p>
     * <p>Description: </p>
     * <p>Copyright: Copyright (c) 2020</p>
     * <p>Company: www.iipcloud.com</p>
     * 
     * @author sliver
     * @date 2020年3月29日
     * @version 1.0
     */
    package com.iipcloud.base;
    
    import java.util.List;
    import java.util.function.Consumer;
    
    import com.google.common.base.Objects;
    
    /**
     * Title: IBean
     * Description:
     * 
     * @author sliver
     * @date 2020年3月29日
     * @since JDK1.8
     */
    public interface IForeachAbleBean {
    
        /**
         * Title: forEach
         * Description: 遍历bean属性(遍历修饰符为public的getXXX方法)
         * 2020年3月29日
         * 
         * @param consumer
         * @param types    指定属性类型集合
         */
        default void forEach(Consumer<BeanProp> consumer, Class<?>... types) {
            List<BeanProp> beanProps = BeanPropCache.ME.getBeanProp(this.getClass());
            boolean noAssignType = types.length == 0;
            for (BeanProp beanProp : beanProps) {
                try {
                    if (noAssignType) {
                        consumer.accept(BeanProp.of(beanProp, this));
                    } else {
                        for (Class<?> item : types) {
                            if (Objects.equal(beanProp.getType(), item)) {
                                consumer.accept(BeanProp.of(beanProp, this));
                                break;
                            }
                        }
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
    
        /**
         * Title: forEachAssignProps
         * Description: 遍历指定的属性
         * 2020年3月29日
         * 
         * @param consumer
         * @param propNames
         */
        default void forEachAssignProps(Consumer<BeanProp> consumer, String... propNames) {
    
            List<BeanProp> beanProps = BeanPropCache.ME.getBeanProp(this.getClass());
            boolean noAssignProp = propNames.length == 0;
            for (BeanProp beanProp : beanProps) {
                try {
                    if (noAssignProp) {
                        consumer.accept(BeanProp.of(beanProp, this));
                    } else {
                        for (String propName : propNames) {
                            if (Objects.equal(beanProp.getName(), propName)) {
                                consumer.accept(BeanProp.of(beanProp, this));
                                break;
                            }
                        }
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
    
        }
    }
    
    

    总结

    1. 从性能的角度来看,直接调用getXXX的方式性能是最好的。反射次之,序列化再反序列化最差。
    2. 与之对应的getXXX方法最是繁琐,反射的实现难度最高,而转JSON在反转为对象是java程序员的的基本技能。
    3. 在上述的实现过程中使用了缓存机制缓存getXXX方法,对性能的提升有一定的效果.

    参考

    1. Guava工具类
    2. HuTool工具类

    相关文章

      网友评论

          本文标题:使用反射实现遍历bean的属性

          本文链接:https://www.haomeiwen.com/subject/rdzuuhtx.html