从配置文件就可以动态的指定要创建哪个类的对象,创建不同的对象不需要修改源代码
classfullpath=com.xtq.fanshe.bean.Cat
method=hi
arg1=\u5c0f\u82b1
arg2=18
bean包下的实体类
import lombok.*;
/**
* @Author: xietianqi
* @Time: 2024-01-28 14:15
* @Description:
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@EqualsAndHashCode
public class Cat {
private String name;
private Integer age;
public static double weight;
private Cat(String name){
this.name=name;
}
public void hi(){
System.out.println("我是"+this.getClass()+"类,我叫"+name+age+"岁了");
}
}
=====================================================
package com.xtq.fanshe.bean;
import lombok.*;
/**
* @Author: xietianqi
* @Time: 2024-01-28 14:15
* @Description:
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@EqualsAndHashCode
public class Dog {
private String name;
private Integer age;
public static double weight;
private Dog(String name){
this.name=name;
}
public void hi(){
System.out.println("我是"+this.getClass()+"类,我叫"+name+age+"岁了");
}
}
使用反射机制创建对象调用方法
package com.xtq.fanshe;
import org.junit.Test;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Properties;
/**
* @Author: xietianqi
* @Time: 2024-01-28 14:14
* @Description: 反射是掌握框架技术的基础
*/
@SuppressWarnings("all")
public class Clazz {
@Test
public void main() throws Exception {
/**
* 读文件
*/
var properties = new Properties();
properties.load(Files.newInputStream(Paths.get("src/main/resources/re.properties")));
var classfullpath = properties.get("classfullpath").toString();
var method = properties.get("method").toString();
var arg1 = properties.get("arg1").toString();
var arg2 = Integer.valueOf(properties.get("arg2").toString());
/**
* 反射创建对象,得到对象所有信息对象
*/
// 根据类名反射得到Class对象
var clazz = Class.forName(classfullpath);
// 得到无参构造
var conNon = clazz.getConstructor();
// 得到有参构造 ..
var con = clazz.getConstructor(String.class, Integer.class);
// 根据clazz类获取对应的对象
var object = con.newInstance(arg1, arg2);
// 得到obj运行类型
System.out.println(object.getClass());
// 得到方法对象
var method1 = clazz.getMethod(method);
// 得到所有权限属性
var fields1 = clazz.getDeclaredFields();
// 得到父类
System.out.println(clazz.getSuperclass());
// 得到接口
var interfaces = clazz.getInterfaces();
/**
* 访问这些成员对象
*/
// 对私有属性进行爆破
fields1[0].setAccessible(true);
// 对obj对象的fields[0]设置值
fields1[0].set(object, "小黄");
// 查看修改的效果
System.out.println(object);
// 设置静态属性值
fields1[2].set(null, 1.2);
// 得到静态的属性
System.out.println(fields1[2].get(null));
// 调用方法,同理静态的null即可
method1.invoke(object);
// 带decalared的是不管权限的只拿本类
// 不带decalared的属性和方法可以拿到父类的
}
}
IOC (inversion of control) 控制反转也叫依赖注入,原理解析xml文件,利用反射机制,在对象工厂中利用反射机制创建对象,目的是为了解耦合,降低对象之间的依赖关系;
举一个不恰当的例子,你在点外卖的时候可以直接打电话给商家订餐,这样你和商家的依赖度就很高,如果借助外卖平台,你就可以在平台上选择不同的商家点单,商家和顾客的耦合度就不高....
而IOC容器就像是这个中间平台一样调度骑手把外卖从商家送到你手上,商家是否能卖出这一单和你是否能吃上饭就取决于这个中间平台;
xml文件
工厂模式+反射类加载
class UserFactory{
...
public static UserDao getDao(){
String className = ...// 解析xml获取类的名字
Class cls = Class.forName(className); // 通过反射创建对象
return (UserDao) cls.newInstance();
}
}
模拟容器类解析xml文件
使用反射机制创建bean对象
通过反射机制调用set方法,给Bean的属性赋值。
实例化对象进入hashmap (真正的是ConcurrentHashMap)
package com.xtq.frame;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Author: xietianqi
* @Time: 2024-01-28 14:15
* @Description:
*/
public class ClassPathXmlApplicationContext {
/**
* 存储bean的Map集合
*/
private Map beanMap = new HashMap<>();
/**
* 在该构造方法中,解析myspring.xml文件,创建所有的Bean实例,并将Bean实例存放到Map集合中。
*
* @param resource 配置文件路径(要求在类路径当中)
*/
public ClassPathXmlApplicationContext(String resource) {
SAXReader reader = new SAXReader();
try {
// 读取配置文件
Document document = reader.read(resource);
// 拿到所有的bean标签
List beanNodes = document.selectNodes("//bean");
// 遍历集合拿到对bean进行处理
beanNodes.forEach(beanNode -> {
Element beanElt = (Element) beanNode;
// 获取id
String id = beanElt.attributeValue("id");
// 获取className
String className = beanElt.attributeValue("class");
try {
// 反射获取对象
Class> clazz = Class.forName(className);
Constructor> constructor = clazz.getDeclaredConstructor();
Object bean = constructor.newInstance();
// 存储到Map集合中
beanMap.put(id, bean);
} catch (Exception e) {
e.printStackTrace();
}
});
///
///给对象属性赋值///
///
// 创建和赋值分步进行解决循环依赖
beanNodes.forEach(beanNode -> {
Element beanElt = (Element) beanNode;
// 获取bean的id
String beanId = beanElt.attributeValue("id");
// 获取所有的property标签
List propertyEls = beanElt.elements("property");
propertyEls.forEach(propertyElt -> {
try {
// 获取属性名
String propertyName = propertyElt.attributeValue("name");
// 获取属性类型
Class> propertyType = beanMap.get(beanId).getClass().getDeclaredField(propertyName).getType();
// 获取set方法名
String setMethodName = "set" + propertyName.toUpperCase().charAt(0) + propertyName.substring(1);
// 获取set方法
Method setMethod = beanMap.get(beanId).getClass().getDeclaredMethod(setMethodName, propertyType);
// 获取value的值
String propertyValue = propertyElt.attributeValue("value");
// 如果是简单属性
if (propertyValue != null) {
// 获取属性类型名
String simpleName = propertyType.getSimpleName();
Object propertyVal = switch (simpleName) {
case "byte", "Byte" -> Byte.valueOf(propertyValue);
case "short", "Short" -> Short.valueOf(propertyValue);
case "int", "Integer" -> Integer.valueOf(propertyValue);
case "long", "Long" -> Long.valueOf(propertyValue);
case "float", "Float" -> Float.valueOf(propertyValue);
case "double", "Double" -> Double.valueOf(propertyValue);
case "boolean", "Boolean" -> Boolean.valueOf(propertyValue);
case "char", "Character" -> propertyValue.charAt(0);
case "String" -> propertyValue;
default -> throw new RuntimeException("这个类还没有设计复杂属性");
};
setMethod.invoke(beanMap.get(beanId), propertyVal);
}
// ...
} catch (Exception e) {
e.printStackTrace();
}
});
});
} catch (DocumentException e) {
e.printStackTrace();
}
}
public Object getBean(String beanId) {
return beanMap.get(beanId);
}
}
测试
package com.xtq.frame;
import com.xtq.fanshe.bean.Cat;
import com.xtq.fanshe.bean.Dog;
/**
* @Author: xietianqi
* @Time: 2024-01-28 14:15
* @Description:
*/
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("src/main/resources/beans.xml");
Object dog = ioc.getBean("dog");
Object cat = ioc.getBean("cat");
// ...
System.out.println(dog.getClass());
System.out.println(cat.getClass());
((Dog) dog).hi();
((Cat) cat).hi();
}
}
beans.xml内容
结果打印
class com.xtq.fanshe.bean.Dog class com.xtq.fanshe.bean.Cat 我是class com.xtq.fanshe.bean.Dog类,我叫小xml狗19岁了 我是class com.xtq.fanshe.bean.Cat类,我叫小xml猫19岁了