1.Spring通过读取配置文件生成对象原理


通过反射创建对象 2种方式: 1.使用Class对象的newInstance()创建该Class对象对应类的实例(要求改Class对应类有默认构造器) 2.先使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法创建该Class对象对应类的实例 --- 该方式,可选择指定的构造器来创建实例


2.关于反射机制


Java反射,可以知道Java类的内部构造,就可以与它进行交互,包括创建新的对象和调用对象中的方法等。 这种交互方式与直接在源代码中使用的效果是相同的,但是又额外提供了运行时刻的灵活性。使用反射的一个最大的弊端是性能比较差 每个类被加载进内存后,系统就会为该类生成一个对应的 java.lang.Class对象,通过该Class对象即可访问到JVM中的这个类 加载完类之后,在堆内存中会产生一个Class类型的对象(一个类只有一个Class对象),这个对象包含了完整的类结构信息,这个Class对象就像一面镜子,可以看到类的结构 程序在运行状态中,可以动态加载一个只有名称的类(全路径),对于任意一个已经加载的类,都能够知道这个类的所有属性和方法, 对于任意一个对象,都能调用它的任意一个方法和属性 用法: 作用1:获取类的内部结构 Java反射API可以获取程序在运行时刻的内部结构,只需短短十几行代码,就可遍历出一个Java类的内部结构,包括:构造方法、声明的域和定义的方法等 java.lang.Class类的对象,可以通过其中的方法来获取到该类中的构造方法、域和方法(getConstructor、getFiled、getMethod) 这三个方法还有相应的getDeclaredXXX版本,区别在于getDeclaredXXX版本的方法只会获取该类自身所声明的元素,而不会考虑继承下来的。 Constructor、Field和Method这三个类分别表示类中的构造方法、域和方法。这些类中的方法可以获取到所对应结构的元数据。 作用2:运行时刻,对一个Java对象进行操作 动态创建一个Java类的对象,获取某个属性的值和调用某个方法 在Java源码中编写的对类和对象的操作,都可以在运行时刻通过反射API来实现 特别说明: clazz.setAccessible(true) --- 可以获取到类中的private属性和private方法 Class对象的获取 1.对象的 getClass()方法 2.类.class属性 --- 最安全,性能最好 3.Class.forName(String classFullName) 动态加载类 --- classFullName是类的全限定名(包.类名) --- 最常用 从Class中获取信息 1.获取信息 构造器、包含方法、包含属性、包含的Annotation、实现的接口,所在包,类名,简称,修饰符等 获取内容 方法签名 构造器 Constructor<T> getConstructor(Class<?>... parameterTypes) 包含的方法 Method getMethod(String name, Class<?>... parameterTypes) 包含的属性 Field getField(String name) 包含的Annotation <A extends Annotation> A getAnnotation(Class<A> annotationClass) 内部类 Class<?>[] getDeclaredClasses() 外部类 Class<?> getDeclaringClass() 所实现的接口 Class<?>[] getInterfaces() 修饰符 int getModifiers() 所在包 Package getPackage() 类名 String getName() 简称 String getSimpleName() 2.判断信息 注解类型、是否是了指定注解、是否是数组、枚举、接口等 判断内容 方法签名 注解类型? boolean isAnnotation() 使用了该Annotation修饰? boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) 匿名类? boolean isAnonymousClass() 数组? boolean isArray() 枚举? boolean isEnum() 原始类型? boolean isPrimitive() 接口? boolean isInterface() obj是否是该Class的实例 boolean isInstance(Object obj) 反射生成并操作对象 通过Method对象执行相应的方法 通过Constructor对象调用对应的构造器来创建实例 通过Field对象直接访问和修改对象的成员变量值



3.通过反射创建对象,模拟Spring的对象池实现

    1.定义json格式的配置文件


         json中模仿Spring的application.xml方式,定义了bean以及bean之间的关系,并未bean设置了属性值


 

{
  "objects": [
    {
      "id": "id1",
      "class": "com.jay.User",
      "fields": [
        {
          "name": "id",
          "value": 101
        },
        {
          "name": "name",
          "value": "jayhe"
        },
        {
          "name": "password",
          "value": "ICy5YqxZB1uWSwcVLSNLcA=="
        }
      ]
    },
    {
      "id": "id2",
      "class": "com.jay.Bean",
      "fields": [
        {
          "name": "usefull",
          "value": true
        },
        {
          "name": "rate",
          "value": 3.14
        },
        {
          "name": "name",
          "value": "bean-name"
        }
      ]
    },
    {
      "id": "id3",
      "class": "com.jay.ComplexBean",
      "fields": [
        {
          "name": "name",
          "value": "complex-bean-name"
        },
        {
          "name": "refBean",
          "ref": "id2"
        }
      ]
    }
  ]
}



      2.对象池类解析配置文件,并以key-value形式保存配置的对象


package com.jay.advanced.java.反射;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.io.CharStreams;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 模拟Spring,创建一个对象池
 * Created by hetiewei on 2017/2/17.
 */
public class ObjectPool {
    private Map<String, Object> pool;

    private ObjectPool(Map<String, Object> pool) {
        this.pool = pool;
    }

    //从指定文件,读取配置信息,返回解析后json数组
    private static JSONArray getObjects(String config) throws IOException {
        //获取输入流
        Reader reader = new InputStreamReader(ClassLoader.getSystemResourceAsStream(config));
        //读取输入流内容,变成json数组返回
        return JSONObject.parseObject(CharStreams.toString(reader)).getJSONArray("objects");
    }

    //根据类名,获取类的对象实例
    private static Object getIntance(String className, JSONArray fields) throws ClassNotFoundException,
            IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        //配置的Class
        Class<?> clazz = Class.forName(className);
        //目标Class的实例对象
        Object targetObject = clazz.newInstance();
        //遍历属性,赋值给实例对象     ---  注意区分,直接赋值,还是赋值引用对象
        if (fields != null && fields.size() != 0) {
            for (int i = 0; i < fields.size(); i++) {
                JSONObject field = fields.getJSONObject(i);
                //需要设置的成员变量名
                String filedName = field.getString("name");
                //需要设置的成员变量的值
                Object fieldValue;
                //如果是8种基本类型或String类型,直接获取value,得到属性赋值
                if (field.containsKey("value")) {
                    fieldValue = field.get("value");
                } else if (field.containsKey("ref")) {
                    //如果是引用类型, 先获得引用对象的id,然后根据id,从对象池中得到引用对象
                    String refBeanId = field.getString("ref");
                    fieldValue = OBJECTPOOL.getObject(refBeanId);
                } else {
                    throw new RuntimeException("没有value 或 ref 引用");
                }

                //构造setterXxx
                String setterName = "set" + filedName.substring(0, 1).toUpperCase() + filedName.substring(1);
                //需要设置成员变量的setter方法
                Method setterMethod = clazz.getMethod(setterName, fieldValue.getClass());
                //调用setter方法设置值
                setterMethod.invoke(targetObject, fieldValue);
            }
        }
        return targetObject;
    }

    private static ObjectPool OBJECTPOOL;

    //创建一个对象池实例(保存多线程安全)
    private static void initSingletonPool() {
        if (OBJECTPOOL == null) {
            synchronized (ObjectPool.class) {
                if (OBJECTPOOL == null) {
                    OBJECTPOOL = new ObjectPool(new ConcurrentHashMap<String, Object>());
                }
            }
        }
    }

    //指定根据的JSON配置文件来初始化对象池
    public static ObjectPool init(String config) {
        //初始化pool
        initSingletonPool();

        //解析Json配置文件
        try {
            JSONArray objects = getObjects(config);
            for (int i = 0; i < objects.size(); i++) {
                JSONObject object = objects.getJSONObject(i);
                if (object == null || object.size() == 0) {
                    continue;
                }
                String id = object.getString("id");
                String className = object.getString("class");

                //初始化Bean,并放入对象池中
                OBJECTPOOL.putObject(id, getIntance(className, object.getJSONArray("fields")));
            }
            return OBJECTPOOL;
        } catch (IOException | ClassNotFoundException |
                InstantiationException | IllegalAccessException |
                NoSuchMethodException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

    public void putObject(String id, Object obj) {
        pool.put(id, obj);
    }

    public Object getObject(String id) {
        return pool.get(id);
    }

    public void clear() {
        pool.clear();
    }

}




3.客户端调用对象池,获取配置中定义的对象


public class Client {

    @Test
    public void client() {
        ObjectPool pool = ObjectPool.init("config.json");
        User user = (User) pool.getObject("id1");
        System.out.println(user);

        Bean bean = (Bean) pool.getObject("id2");
        System.out.println(bean);

        ComplexBean complexBean = (ComplexBean) pool.getObject("id3");
        System.out.println(complexBean);
    }
}


4.解析xml方式生成对象池