美文网首页Java 杂谈每天一个知识点java爱好者
java Introspector(内省) 的使用场景以及为什么

java Introspector(内省) 的使用场景以及为什么

作者: Sharember | 来源:发表于2018-04-17 21:55 被阅读6次

    内省一般写业务代码的时候是用不到的,大部分是在写一些框架或者工具的时候会用到。

    比如说 spring 初始化 bean 的场景:

    spring 提供 ioc 的机制,使用者在 xml 中配置 bean,spring 启动的时候加载 bean

    假设有下面的类:

    public class User {
    
        private String name;
    
        private int age;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    }
    

    我们正常使用的话,可以这样写:

    User u = new User();
    u.setName("chengfan");
    u.setAge(22);
    

    这是完全没有问题的,但是,当我们把这个类交给 spring 的时候,问题就出现了: spring 是一个已有的框架, 它并不知道 User 这个类,也并不知道它有哪些方法、哪些属性。

    所以 spring 需要使用一种特殊的手段来拿到这些信息,我们熟知的方法是反射。

    spring.xml 如下:

        <bean id="user" class="cn.fanhub.jysk.spring.introspector.User">
            <property name="name" value="chengfan" />
            <property name="age" value="22" />
        </bean>
    

    利用反射,我们会这样写:

    @Test
    public void test1 () throws Exception {
        //模拟从 xml 中获得到了数据
        //<bean id="user" class="cn.fanhub.jysk.spring.introspector.User">
        //    <property name="name" value="chengfan" />
        //    <property name="age" value="22" />
        //</bean>
    
        String clazz = "cn.fanhub.jysk.spring.introspector.User";
        Map<String, Object> properties = new HashMap<>();
    
        properties.put("Name", "chengfan");
        properties.put("Age", 22);
    
        reflect(clazz, properties);
    }
    
    @SuppressWarnings("unchecked")
    public void reflect(String clazz, Map<String, Object> properties) throws Exception {
        //反射创建实例
        Class target = Class.forName(clazz);
        Object bean = target.newInstance();
    
        //初始化容器时,调用setter注入
        for (Entry<String, Object> entry : properties.entrySet()) {
            String _setName = "set" + entry.getKey();
            if ("name".equalsIgnoreCase(entry.getKey())) {
                Method setMethod = target.getMethod(_setName, String.class);
                setMethod.invoke(bean, entry.getValue().toString());
            } else {
                Method setMethod = target.getMethod(_setName, int.class);
                setMethod.invoke(bean, Integer.parseInt(entry.getValue().toString()));
            }
        }
    
        // show
        for (Entry<String, Object> entry : properties.entrySet()) {
            String _getName = "get" + entry.getKey();
            if ("name".equalsIgnoreCase(entry.getKey())) {
                Method setMethod = target.getMethod(_getName);
                System.out.println(setMethod.invoke(bean));
            } else {
                Method setMethod = target.getMethod(_getName);
                System.out.println(setMethod.invoke(bean));
            }
        }
    }
    /*
    22
    chengfan
    */
    

    都是硬编码,不具备任何观赏性,只是为了演示如何实现。

    虽然这样可以达到目的,但是我们获取 get 和 set 方法的手段不够优雅。

    使用内省的方式实现如上功能:

    @Test
    public void test1 () throws Exception {
        //模拟从 xml 中获得到了数据
        //<bean id="user" class="cn.fanhub.jysk.spring.introspector.User">
        //    <property name="name" value="chengfan" />
        //    <property name="age" value="22" />
        //</bean>
    
        String clazz = "cn.fanhub.jysk.spring.introspector.User";
        Map<String, Object> properties = new HashMap<>();
    
        properties.put("name", "chengfan");
        properties.put("age", 22);
        introspector(clazz, properties);
    }
        
    public void introspector(String clazz, Map<String, Object> properties) throws Exception {
        //反射创建实例
        Class target = Class.forName(clazz);
        Object bean = target.newInstance();
    
        BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
        PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
    
        for (PropertyDescriptor pd : pds) {
            Method setMethod = pd.getWriteMethod();
            String fieldName = pd.getName();
    
            if ("name".equalsIgnoreCase(fieldName)) {
                setMethod.invoke(bean, properties.get(fieldName));
            } else if ("age".equalsIgnoreCase(fieldName)){
                setMethod.invoke(bean, properties.get(fieldName));
            }
        }
    
    
        // show
        for (PropertyDescriptor pd : pds) {
            System.out.println(pd.getReadMethod().invoke(bean));
        }
    }
    /*
    22
    chengfan
    class cn.fanhub.jysk.spring.introspector.User  // 先忽略它
    */
    

    很明显,内省显得更加专业。当然,它的操作依旧不方便,比如参数类型的判断。

    首发自 个人网站

    相关文章

      网友评论

        本文标题:java Introspector(内省) 的使用场景以及为什么

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