IoC(Inversion of Control) 控制反转,是spring框架的核心。DI(dependency injection)依赖注入是IoC 的核心。
IoC控制反转到底反转了什么?
依赖对象的创建和依赖关系的形成,解耦。
spring不用自己创建对象,只需要在配置文件中配置属性就可以对其实现赋值。依赖注入底层是如何实现的呢,今天就用反射来手动实现getBean()方法。
项目中需要用到dom4j的jar包来解析spring的xml配置文件。下载链接如下:https://dom4j.github.io/
工程的总体目录如下,代码简单,注释详细。
总目录
实体类Student的代码如下:四个不同属性 ,分别设置setter和getter方法,重写toString方法
package com.entity; public class Student { private String name; private int age; private char gender; private double salary; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public char getGender() { return gender; } public void setGender(char gender) { this.gender = gender; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + ", gender=" + gender + ", salary=" + salary + "]"; }
}
|
最重要的ApplicationContext如下,主要是解析xml文件,得到类的对象并赋值。
package com.factory; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.List; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; public class ApplicationContext { private String configFileName; public ApplicationContext(String configFileName){ this.configFileName = configFileName; } public Object getBean(String id)throws Exception{ SAXReader reader = new SAXReader(); Document doc = reader.read(this.getClass().getResourceAsStream("../../"+configFileName)); Element root = doc.getRootElement(); List<Element> bs = root.elements(); for(Element b : bs){ String beanId = b.attributeValue("id"); if(id.equals(beanId)){ String beanClass = b.attributeValue("class"); Class c = Class.forName(beanClass); Object obj = c.newInstance(); List<Element> ps = b.elements(); for(Element p : ps){ String propertyName = p.attributeValue("name"); String propertyValue = p.attributeValue("value"); String setterName = "set" + propertyName.substring(0,1).toUpperCase() + propertyName.substring(1); Field field = c.getDeclaredField(propertyName); Class fieldType = field.getType(); Method setter = c.getDeclaredMethod(setterName,fieldType); String fieldTypeName = fieldType.getSimpleName(); if("String".equals(fieldTypeName)){ setter.invoke(obj, propertyValue); } else if("int".equals(fieldTypeName)){ setter.invoke(obj,Integer.parseInt(propertyValue)); } else if("double".equals(fieldTypeName)){ setter.invoke(obj,Double.parseDouble(propertyValue)); } else if("char".equals(fieldTypeName)){ setter.invoke(obj, propertyValue.charAt(0)); } } return obj; } } return null; } }
|
xml配置文件如下:
<?xml version="1.0" encoding="UTF-8"?> <beans> <bean id="stu" class="com.entity.Student"> <property name="name" value="zhangsan" /> <property name="age" value="25"/> <property name="gender" value="男"/> <property name="salary" value="16666" /> </bean> </beans>
|
测试类如下:
package com.test; import com.entity.Student; import com.factory.ApplicationContext; public class TestSpringBean { public static void main(String[] args) throws Exception { ApplicationContext ac = new ApplicationContext("spring.xml"); Student stu = (Student)ac.getBean("stu"); System.out.println(stu); } }
|
测试结果显示成功得到stu对象,并且成功为属性赋值。
其实spring框架底层就是用反射和配置文件来实现new对象,setter方法为属性赋值的。
所有框架底层都要用到反射,因为框架写好在前,我们使用在后。