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,來實現對象生命週期的管理,有張圖可以參考下: