spring的两大思想,IOC和AOP,IOC实现对象的创建和生命周期管理,AOP面向切面编程,将和业务逻辑没有直接关联的业务代码从主业务代码中抽离出来,需要的时候再切入进去,实现程序的可插拔和弱耦合.
spring根据一个配置文件就能帮助我们创建对象,并注入属性.于是乎,就自己写个程序去解析xml,根据里面的配置,往类里面的属性注入值,最终实现的效果是这样的:
Step1:新建一个配置文件applicationContext.xml,当然不叫这个名也是可以的.
Step2:创建两个实体,Person和Dog
public class Dog {
private String type;
private String color;
@Override
public String toString() {
return "Dog [type=" + type + ", color=" + color + "]";
}
public void setType(String type) {
this.type = type;
}
public void setColor(String color) {
this.color = color;
}
}
public class Person {
private String name;
private Integer age;
private Dog dog;
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setDog(Dog dog) {
this.dog = dog;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", dog=" + dog + "]";
}
}
重写toString()方法,目的是让打印结果更直接;
Step3:核心程序,解析xml,往两个实体注入属性,廉颇老将军不仅能吃饭还左牵黄右擎苍~
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.File;
import java.util.Objects;
import javax.xml.parsers.DocumentBuilderFactory;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
public class SpringMockTest {
@Test
public void testSpringMock() throws Exception {
// 加载xml文件
String path = Objects.requireNonNull(SpringMockTest.class.getClassLoader().getResource("applicationContext.xml")).getPath();
File file = new File(path);
// 解析文件成DOM
Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(file);
// 获取根元素
Element rootEle = document.getDocumentElement();
// 获取所有的bean元素对象
NodeList beans = rootEle.getElementsByTagName("bean");
Element personBeanEle = (Element) beans.item(0);
// 获取person元素的属性值
NodeList PersonBeanProperties = personBeanEle.getElementsByTagName("property");
Element personBeanPropEle1 = (Element) PersonBeanProperties.item(0);
Element personBeanPropEle2 = (Element) PersonBeanProperties.item(1);
Element personBeanPropEle3 = (Element) PersonBeanProperties.item(2);
// 获取Person的字节码对象
Class<?> personClz = Class.forName(personBeanEle.getAttribute("class"));
Object person = personClz.newInstance();
// 获取Person的属性描述器
PropertyDescriptor[] personPds = Introspector.getBeanInfo(personClz, Object.class).getPropertyDescriptors();
//运用内省机制注入属性值
for (PropertyDescriptor personPd : personPds) {
if (personPd.getName().equals(personBeanPropEle1.getAttribute("name"))) {
personPd.getWriteMethod().invoke(person, personBeanPropEle1.getAttribute("value"));
} else if (personPd.getName().equals(personBeanPropEle2.getAttribute("name"))) {
personPd.getWriteMethod().invoke(person, Integer.parseInt(personBeanPropEle2.getAttribute("value")));
} else {
Object dog = null;
for (int i = 0; i < beans.getLength(); i++) {
Element beanEle = (Element) beans.item(i);
if (personBeanPropEle3.getAttribute("ref").equals(beanEle.getAttribute("id"))) {
//通过反射获得dog对象
Class<?> dogClz = Class.forName(beanEle.getAttribute("class"));
dog = dogClz.newInstance();
//获取dog对象的属性节点列表
NodeList dogBeanProperties = beanEle.getElementsByTagName("property");
//获取dog对象属性描述器
PropertyDescriptor[] dogPds = Introspector.getBeanInfo(dogClz, Object.class).getPropertyDescriptors();
for (PropertyDescriptor dogPd : dogPds) {
for (int j = 0; j < dogBeanProperties.getLength(); j++) {
Element dogBeanPropEle = (Element)dogBeanProperties.item(j);
if (dogPd.getName().equals(dogBeanPropEle.getAttribute("name"))) {
//如果xml中属性名和dog对象属性名一致,则注入值
dogPd.getWriteMethod().invoke(dog, dogBeanPropEle.getAttribute("value"));
}
}
}
}
}
//同理,person对象注入相应属性值
personPd.getWriteMethod().invoke(person, dog);
}
}
System.out.println(person);
}
}
到此就结束了,代码很简单,主要是理解一遍spring IOC思想.
spring对bean进行实例化,默认bean是单例.
通过查看源码我发现spring实现了很多的BeanPostProcessor,来实现对象生命周期的管理,有张图可以参考下: