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方式生成对象池