Spring IoC(Inversion of Control)也叫DI(Dependency Injection)。
控制反轉指的是創建對象操作、對象屬性的賦值操作的控制權由業務代碼反轉到Spring容器。
依賴注入指的是對象的屬性賦值操作由Spring在容器中找到對應的對象后完成操作。
兩個術語表達的角度不同,但是同一個意思。也就是兩點:
- 對象的初始化交給Spring容器去做;
- 對象屬性的賦值交給Spring容器去做。
下面用簡易版的代碼,模擬通過XML配置完成Spring IoC的過程。
Spring IoC的基本實現過程是:
有一個Bean工廠,里面維護了一個Bean容器,在Bean工廠初始化的時候去解析配置文件。在配置文件中找到所有的<bean>,通過<bean>的id和class屬性來初始化成對應的bean對象,然后放到Bean容器里。比如下面的applicationContext.xml
<?xml version="1.0" encoding="utf-8"?>
<beans>
<bean id="car" class="tk.zhun.j2se.ioc.Car" />
</beans>
然后寫一個BeanFactory的類來讀取它,并且初始化所有的bean到容器中。并提供一個從容器中通過類名獲取bean的方法getBean(String beanName):
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
public class BeanFactory {
private static HashMap<String,Object> container = new HashMap<>();
public BeanFactory() throws Exception{
InputStream ip = BeanFactory.class.getClassLoader()
.getResourceAsStream("tk/zhun/j2se/ioc/applicationContext.xml");
Document doc = null;
SAXReader xmlReader = new SAXReader();
doc = xmlReader.read(ip);
Element root = doc.getRootElement();
List<Element> beanList = root.elements("bean");
for (Element bean:beanList) {
String id = bean.attributeValue("id");
String clazz = bean.attributeValue("class");
Object o = Class.forName(clazz).newInstance();
container.put(id,o);
}
}
public Object getBean(String beanName) throws Exception {
return container.get(beanName);
}
}
測試代碼:
public class Car {
public void run(){
System.out.println("A car is running......");
}
}
public class Client {
public static void main(String[] args) throws Exception {
BeanFactory beanFactory = new BeanFactory();
Car car = (Car)beanFactory.getBean("car");
car.run();
}
}
運行結果:
A car is running......
TIP:這里只演示了第1步(對象的初始化交給Spring容器去做),第2步沒有實現,思路就是在解析XML之后,對<bean>中帶有<property>標簽的bean對象,通過反射獲取該屬性setter方法的Method對象,然后調用該Method對象的invoke方法,完成賦值。