Java 杂谈每天一个知识点java爱好者

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

2018-04-17  本文已影响6人  Sharember

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

比如说 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  // 先忽略它
*/

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

首发自 个人网站

上一篇下一篇

猜你喜欢

热点阅读