内省

内省的类和方法

Java提供了API用来访问某个属性的getter/setter方法:
Introspector类的getBeanInfo方法获取某个对象的BeanInfo信息;
通过BeanInfo来获取属性的描述器PropertyDescriptor


1、Introspector类:
Introspector.getBeanInfo(Class<?> beanClass)

2、BeanInfo类:
PropertyDescriptor[] getPropertyDescriptors() 获得 beans PropertyDescriptor
MethodDescriptor[] getMethodDescripors() 获得beans MethodDescriptor

3、PropertyDescriptor类:
Method getReadMethod()  获得用于读取属性值的方法(即get方法)
Method getWriteMethod() 获得用于写入属性值的方法(即set方法)

4、MethodDescriptor类:
Method getMethod() 获得此MethodDescriptor封装的方法

Config.properties

bean.name=com.vince.Introspector.Config
bean.username=admin
bean.password=12345
bean.url=https://www.baidu.com

Config.java

package com.vince.Introspector;

public class Config {
    private String username;
    private String password;
    private String url;

    public Config() {
    }

    public Config(String username, String password, String url) {
        this.username = username;
        this.password = password;
        this.url = url;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    @Override
    public String toString() {
        return "Confog{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", url='" + url + '\'' +
                '}';
    }
}

BeanFectory.java

package com.vince.Introspector;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;


public class BeanFectory {

    private static Properties p = new Properties(); //p是配置文件的对象,为什么要用静态,因为如下配置文件输入流是放在了静态代码块里的

    //使用静态代码块读取配置文件:保证配置属性在类被加载的时候只读取一次,避免重复读取
    static {
        InputStream resourceAsStream =       //即读取配置文件生成输入流
                Thread.currentThread().getContextClassLoader().getResourceAsStream("com/vince/Introspector/Config.properties"); //这里路径是配置文件的完整路径
        try {
            p.load(resourceAsStream);        //静态代码块中只能是调用静态的属性的方法;将配置文件的输入流加载到配置文件的对象p中(即配置文件里的所有信息就可以获取到了)
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //创建JavaBean的类{即调用配置文件里的具体属性值,创建一个具体的Config的类对象}
    public static Object createBean(String name){      //因为配置文件对象是静态的属性,所以这里方法也必须是静态的
        Object bean=null;
        String beanName = p.getProperty(name);         //这里的name是配置文件里的包完整路径的配置名称:bean.name=com.vince.Introspector.Config  的 "bean.name",继而可由bean.name获取它的value
                                                       //即通过配置文件里的key(name的值),得到对应key的值
        try {
            Class<?> aClass = Class.forName(beanName); //可由包的完整路径通过反射获取Class类的对象信息
            bean=aClass.newInstance();                 //通过Class类对象,获取原目标类的对象

            BeanInfo beanInfo = Introspector.getBeanInfo(aClass);                         //通过内省(Introspector),用反射的Class类信息获取javaBean的描述信息
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); //通过内省(beanInfo),用javaBean的描述信息获取源目标类的所有属性信息
            int len = propertyDescriptors.length;
            for (int i = 0; i < len; i++) {
                String propertyName = propertyDescriptors[i].getName();       //propertyDescriptors[i].getName(),遍历源目标类的所有属性的名称
                Method writeMethod = propertyDescriptors[i].getWriteMethod(); //遍历获取源目标类所有属性的set方法
                if("username".equals(propertyName)){
                    writeMethod.invoke(bean, p.getProperty("bean.username")); //相当于调用类属性的set方法,为属性设置具体的值,这里是把配置文件里的key对应的value具体值设置给该属性
                }else if("password".equals(propertyName)){
                    writeMethod.invoke(bean, p.getProperty("bean.password"));
                }else if("url".equals(propertyName)){
                    writeMethod.invoke(bean, p.getProperty("bean.url"));
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IntrospectionException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return bean;
    }

}

BeanTest.java

package com.vince.Introspector;

import org.junit.Test;
public class BeanTest {
    @Test
    public void getbeantest(){
        //因为createBean是一个静态属性方法,所以呢,就不用创建对象的方式调用,可用:类名.方法名 直接调用
        //BeanFectory bf = new BeanFectory();
        //Object bean = bf.createBean("bean.name");
        Config bean = (Config)BeanFectory.createBean("bean.name");
        System.out.println(bean.toString());
        /**
         * 为什么要这么复杂的获取一个对象呢?
         * 为了提高代码的可维护性,对于属性值,以后只需更改配置文件即可实现创建一个新的对象
         */
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。