回顾
上篇文章已经演示了spring最基础的IOC功能 演示地址
先做一个简单的回顾。
public class DemoMain {
public static void main(String[] args) {
//创建Spring上下文加载bean.xml
ApplicationContext app=new ClassPathXmlApplicationContext("bean.xml");
//获取user实例
User user = (User)app.getBean("user");
//打印user
System.out.println(user);
}
}
-
由以上代码可知,spring通过读取XML的内容(对象的包名类名、变量名称与值),通过反射动态的创建一个对象。
-
既然我们已经知道了原理,那么我们就可以通过这种方式自己手动实现一个简单版的Spring IOC功能
手动实现简单IOC功能
实现简单的IOC可以分为两步
不熟悉的童鞋可以点击超链接回顾基础(大神请绕道)
MySingleIOC// IOC 的实现类,实现了上面所说的2个步骤
Main// IOC 演示类
User// IOC 测试使用的 bean
Home // 同上
MySpring.xml // bean 配置文件
容器实现类 MySingleIOC的代码:
public class MySingleIOC {
//模拟spring容器 用于保存bean的键值对的hashMap
private Map<String, Object> beanMap = new HashMap<>();
public MySingleIOC() { }
//有参构造函数 初始化xml
public MySingleIOC(String xmlName) throws Exception {
loadbean(xmlName);
}
//私有方法加载bean
private void loadbean(String xmlName) throws Exception {
//第一步 读取 xml文件
InputStream resourceAsStream = MySingleIOC.class.getClassLoader().getResourceAsStream(xmlName);
if (resourceAsStream == null) {
//当找不到xml抛出异常
throw new FileNotFoundException("该XML文件无法找到:" + xmlName);
}
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = dbf.newDocumentBuilder();
Document parse = documentBuilder.parse(resourceAsStream);
resourceAsStream.close();
NodeList beanList = parse.getElementsByTagName("bean");
//遍历bean标签
for (int i = 0; i < beanList.getLength(); i++) {
Node node = beanList.item(i);
if (node instanceof Element) {
Element el = (Element) node;
String beanId = el.getAttribute("id");
String beanClass = el.getAttribute("class");
//第二步 反射动态获取对象
Class beanClazz = null;
try {
//加载beanClass
beanClazz = Class.forName(beanClass);
} catch (ClassNotFoundException e) {
e.getMessage();
return;
}
//创建Bean对象
Object beanObj = beanClazz.newInstance();
NodeList propertyList = el.getElementsByTagName("property");
//遍历子标签property
for (int j = 0; j < propertyList.getLength(); j++) {
Node item = propertyList.item(j);
if (item instanceof Element) {
Element ele = (Element) item;
//拿到变量名称
String name = ele.getAttribute("name");
//拿到变量值(不一定都是String类型下面要做转换)
String value = ele.getAttribute("value");
//通过反射将bean对象指定属性
Field declaredField = beanObj.getClass().getDeclaredField(name);
//将私有属性设置为可访问
declaredField.setAccessible(true);
//获取成员属性的类型名称,若非字符串类型,则需要做相应转换
String fieldTypeName = declaredField.getType().getName();
Object o = ParamType(fieldTypeName, value);
//为该成员属性赋值
declaredField.set(beanObj, o);
//将该字段属性设置值
beanMap.put(beanId, beanObj);
}
}
}
}
}
//转换运行时参数类型(做简单演示,目前只有String Integer和int可扩展)
private Object ParamType(String fieldTypeName, String value) {
Object obj = null;
//判断该成员属性是否为int或Integer类型
if ("int".equals(fieldTypeName) || "java.lang.Integer".equals(fieldTypeName)) {
//转换为int类型并为该成员属性赋值
int intFieldValue = Integer.parseInt(value);
obj = intFieldValue;
}//判断该成员属性是否为String类型
if ("java.lang.String".equals(fieldTypeName)) {
//为该成员属性赋值
obj = value;
}//判断另外类型同理
//if(){ }
return obj;
}
//获取bean
public Object getBean(String beanName) {
Object bean = beanMap.get(beanName);
if (bean == null) {
throw new IllegalArgumentException("无法实例化该名称的bean,请确定名称是否正确 " + beanName);
}
return bean;
}
}
测试使用的 bean 代码:
public class User {
private String name;
private Integer age;
private String sex;
//省略get、set方法
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
}
public class Home {
private String country;
private String province;
private String homeCity;
private String workCity;
//省略get、set方法
@Override
public String toString() {
return "Home{" +
"country='" + country + '\'' +
", province='" + province + '\'' +
", homeCity='" + homeCity + '\'' +
", workCity='" + workCity + '\'' +
'}';
}
}
bean 配置文件MySpring.xml 内容:
<beans>
<bean id="user" class="com.xiaoli.model.User">
<property name="name" value="小立"></property> <!--姓名-->
<property name="age" value="22"></property> <!--年龄-->
<property name="sex" value="男"></property> <!--性别-->
</bean>
<bean id="home" class="com.xiaoli.model.Home">
<property name="country" value="中国"></property> <!--国家-->
<property name="province" value="湖北"></property> <!--省份-->
<property name="homeCity" value="宜昌"></property> <!--家乡城市-->
<property name="workCity" value="杭州"></property> <!--工作城市-->
</bean>
</beans>
新建一个演示类DemoMain
public class DemoMain {
public static void main(String[] args) throws Exception{
MySingleIOC ioc=new MySingleIOC("com/xiaoli/resouorce/MySpring.xml");
User user = (User)ioc.getBean("user");
System.out.println(user);
Home home = (Home)ioc.getBean("home");
System.out.println(home);
}
}
得到结果:
与之前创建的spring项目结果相同;
以上是简单 IOC 实现的全部内容,难度不大,代码简洁。一个行业小白的理解,如果有错误,望指出,以便及时更正!谢谢!
版权声明:本文为博主原创文章,未经博主允许不得转载 https://blog.csdn.net/qq_44614710/article/details/86763077