java反射与内省

反射

通过程序运行时信息来获取类或对象的类信息
获取Class对象的三种方法

Class class = dog.getCalss();
Class class = Dog.class;
Class class = Class.forName("com.vince.Dog");//会有ClassNotFoundExeception

通过反射实例化对象和获取对象信息

package reflection;

import java.lang.reflect.*;

public class ReflectionDemo {

    public static void main(String[] args) {
        Dog dog = new Dog("dabao",5,"白色","藏獒");
        Class dogClass = dog.getClass();
        //通过反射实例化对象
        try {
            //Dog inflectDog = (Dog)dogClass.newInstance("dwr");//jdk1.9之后不推荐使用
            Dog inflectDog = (Dog)dogClass.getDeclaredConstructor(String.class, int.class, String.class, String.class).newInstance("xiaobai",3,"黑色","咖啡毛");
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        //获取构造方法
        Constructor[] constructors = dogClass.getConstructors();//获取所有构造方法
        for (int i = 0; i < constructors.length; i++) {
            System.out.println(constructors[i].getName());//构造参数名
            System.out.println(constructors[i].getParameterCount());//参数数目
        }
        try {
            Constructor constructor = dogClass.getConstructor(String.class, int.class, String.class, String.class);//根据变量类型获取指定的构造方法
            //之后就可以调用上面的newInstance方法实例化一个对象
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        //获取类中的所有属性
        Field[] fields = dogClass.getFields();//获取所有非private的属性
        System.out.println(fields.length);
        Field[] declaredFields = dogClass.getDeclaredFields();//获取所有属性
        System.out.println(declaredFields.length);
        for (int i = 0; i < declaredFields.length; i++) {
            int modifiers = declaredFields[i].getModifiers();
            System.out.println(Modifier.toString(modifiers)+" "+declaredFields[i].getType()+" "+declaredFields[i].getName());
        }

        //获取包对象的包信息
        Package aPackage = dogClass.getPackage();
        System.out.println(aPackage.getName());

        //获取方法
        //获取所有非private方法,包括父类的方法
        Method[] methods = dogClass.getMethods();
        for (int i = 0; i < methods.length; i++) {
            System.out.println(methods[i]);
            if(methods[i].getName().equals("toString")){
                try {
                    String s = (String)methods[i].invoke(dog);//调用方法
                    System.out.println(s);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println("-------------");
        //获取当前类的所有方法(包括private),不包括父类
        Method[] methods1 = dogClass.getDeclaredMethods();
        for (int i = 0; i < methods1.length; i++) {
            System.out.println(methods1[i]);
            if(methods1[i].getName().equals("set")){
                //设置私有方法可以被访问(去除访问修饰符的检查)
                methods1[i].setAccessible(true);
                try {
                    methods1[i].invoke(dog);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

内省

Java中提供的一套用来访问某个属性的getter/setter方法的API

读取配置文件案例

package instrospector;
//配置类
public class Config {
    private String username;
    private String password;
    private String url;

    public String getUsername() {
        return username;
    }

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

    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 "Config{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", url='" + url + '\'' +
                '}';
    }
}

//配置文件config.properties
bean.name= instrospector.Config
bean.username = hello
bean.password = 123
bean.url = http://www.xiaoming.net.cn

package instrospector;
//读取配置文件的工厂
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 BeanFactory {
    private static Properties prop = new Properties();
    //使用静态代码块读取配置文件
    static{
        InputStream in = Thread.currentThread().getContextClassLoader()
                .getResourceAsStream("instrospector/config.properties");
        try {
            prop.load(in);//加载文件
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取一个Bean
     * @param name
     * @return
     */
    public static Object getBean(String name){
        Object bean = null;
        String beanName = prop.getProperty(name);
        try {
            Class<?> aClass = Class.forName(beanName);
            bean = aClass.getDeclaredConstructor().newInstance();
            //通过类信息获取javaBean的描述信息
            BeanInfo beanInfo = Introspector.getBeanInfo(aClass);
            //通过javaBean的描述信息,获取该类的所有属性描述器
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (int i = 0; i < propertyDescriptors.length; i++) {
                //获取属性名
                String propertyName = propertyDescriptors[i].getName();
                //获取某个属性的写方法
                Method writeMethod = propertyDescriptors[i].getWriteMethod();
                if("username".equals(propertyName)){
                    writeMethod.invoke(bean,prop.getProperty("bean.username"));
                }else if("password".equals(propertyName)){
                    writeMethod.invoke(bean,prop.getProperty("bean.password"));
                }else if("url".equals(propertyName)){
                    writeMethod.invoke(bean,prop.getProperty("bean.url"));
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IntrospectionException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return bean;
    }
}

package instrospector;
//测试
public class BeanTest {
    public static void main(String[] args) {
        Config bean = (Config)BeanFactory.getBean("bean.name");
        System.out.println(bean);
    }
}

AOP编程

面向切面编程,将一些与业务代码无关的代码放在另外的一个地方,让业务代码执行的时候跟着执行

//业务接口
public interface IManager {
    public void add(String item);
}

import java.util.ArrayList;
//业务内容
public class IManagerImpl implements IManager{
    private ArrayList<String> list = new ArrayList<>();
    @Override
    public void add(String item) {
        list.add(item);
    }
}

//通知(切面内容)
public interface Advice {
    public void beforeAdvice();
    public void afterAdvice();
}

//切面内容实现类
public class LogAdvice implements Advice{

    @Override
    public void beforeAdvice() {
        System.out.println("start time:"+System.currentTimeMillis());
    }

    @Override
    public void afterAdvice() {
        System.out.println("end time:"+System.currentTimeMillis());
    }
}

//配置文件
bean.target = aop.IManagerImpl
bean.advice = aop.LogAdvice
bean = aop.ProxyFactoryBean

//动态代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyFactoryBean implements InvocationHandler {
    private Object target;//业务对象
    private Advice advice;//切面对象

    public Object getTarget() {
        return target;
    }

    public void setTarget(Object target) {
        this.target = target;
    }

    public Advice getAdvice() {
        return advice;
    }

    public void setAdvice(Advice advice) {
        this.advice = advice;
    }

    /**
     * 获取代理对象
     */
    public Object getProxy(){
        Object proxy = Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                this);
        return proxy;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        advice.beforeAdvice();
        Object object = method.invoke(target,args);
        advice.afterAdvice();
        return object;
    }
}

//代理类的处理加工工厂
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 BeanFactory {
    private Properties prop = new Properties();

    //读取配置文件
    public BeanFactory(InputStream in){
        try {
            prop.load(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取一个bean实例
     * @param name
     * @return
     */
    public Object getBean(String name){
        String className = prop.getProperty(name);
        Object bean = null;
        try {
            //获取ProxyFactoryBean的class对象
            Class<?> aClass = Class.forName(className);//创建一个代理类
            bean = aClass.getDeclaredConstructor().newInstance();

            //根据配置文件实例化target,advice对象
            Object target = Class.forName(prop.getProperty(name+".target")).getDeclaredConstructor().newInstance();
            Object advice = Class.forName(prop.getProperty(name+".advice")).getDeclaredConstructor().newInstance();
            //通过内省获取代理类属性信息
            BeanInfo beanInfo = Introspector.getBeanInfo(aClass);
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for(PropertyDescriptor pd:propertyDescriptors){
                String propertyName = pd.getName();
                Method writeMethod = pd.getWriteMethod();
                if("target".equals(propertyName)){
                    writeMethod.invoke(bean,target);
                }else if("advice".equals(propertyName)){
                    writeMethod.invoke(bean,advice);
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IntrospectionException e) {
            e.printStackTrace();
        }

        return bean;
    }

}

//测试
import java.io.InputStream;
public class AOPTest {
    public static void main(String[] args) {
        //读取配置文件
        InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("aop/bean.properties");
        //创建Bean的工厂对象
        BeanFactory beanFactory = new BeanFactory(in);
        //获取代理对象
        ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean)beanFactory.getBean("bean");
        IManager proxy = (IManager) proxyFactoryBean.getProxy();//反射得到的代理实例
        proxy.add("我是一只猫");
    }
}