在這以前先介紹Spring及Spring IOC的基本概念:
Spring容器-一個IOC容器,用以管理程序中的各類對象以及他們之間的聯繫。git
好比說,我建立這樣一個類:github
public class OrderDao {
public void selcet(){
System.out.println("select");
}
}
複製代碼
而後在resource資源目錄下新建config.xml文件,將配置信息貼入其中:web
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:contex="http://www.springframework.org/schema/context"
xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- bean definitions here -->
</beans>
複製代碼
本來我新建一個它的實例須要經過new,可是有了IOC以後,我只須要在config.xml中聲明 <bean id="OrderDao" class="com.github.hcsp.OrderDao"/>
而後經過工廠方法獲取:spring
//接受一個config.xml路徑
BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:db/mybatis/config.xml");
//最核心的API
OrderDao orderDao = (OrderDao) beanFactory.getBean("OrderDao");
//拿到的這個Bean默認狀況下是單例的既同一時刻只能存在一個類的實例
複製代碼
同時還能夠基於註解聲明類之間存在的依賴關係,好比這種狀況:
bash
public class OrderService {
private OrderDao orderDao;
public void doSomething() {
orderDao.selcet();
}
}
複製代碼
OrderService中存在對OrderDao的引用,本來是須要咱們本身去管理對象之間的依賴關係,可是有了Spring以後,咱們只須要聲明他們之間存在依賴關係,管理他們這種關係的工做就由Spring去完成了。如何實現這個過程呢?這時候要是你直接經過beanFactory去新建OrderService的實例,是沒有這種依賴關係的:服務器
OrderService orderService = (OrderService) beanFactory.getBean("OrderService");
複製代碼
public class OrderService {
@Resource
private OrderDao orderDao;
public void doSomething() {
orderDao.selcet();
}
}
複製代碼
接着在<beans>標籤中添加<contex:annotation-config/>
,將schemaLocation增長爲:mybatis
xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
複製代碼
狀況就不同了: 架構
M-model(模型) 表明數據。
V-view(視圖)表明網頁,JSP等用以展現模型中的數據。
C-controller(控制器)將不一樣的數據顯示在不一樣的視圖上,這個過程由Servlet(小服務器)完成。框架
重新建properties文件開始,記得前面講Mybatis的動態SQL配置日誌那裏,新建了一個log4j.properties文件,其中都是一個個的
XXX=XXX
。這其實相似於HashMap的鍵值對(Properties類繼承了HashTable),前面是對象名,後面是對象的全限定類型。
在咱們的IOC容器中,添加本身的映射。新建一個beans.properties文件,寫入如下數據:
ui
orderDao=com.github.hcsp.ioc.OrderDao
userDao=com.github.hcsp.ioc.UserDao
userService=com.github.hcsp.ioc.UserService
orderService=com.github.hcsp.ioc.OrderService
複製代碼
接下來用這樣一個例子演示IOC加載類之間依賴關係的原理:
/**
* 從.properties文件中獲取信息
*
* @return 一個properties類
*/
public static Properties getAndLoadProperties() {
Properties properties = new Properties();
try {
properties.load(MyIoCContainer.class.getResourceAsStream("/beans.properties"));
} catch (IOException e) {
throw new RuntimeException("properties路徑有誤"+e);
}
return properties;
}
複製代碼
/**
* 遍歷.properties文件中的內容,生成value的實例,將<key,value的實例>逐個映射到HashMap中
*
* @param properties 加載後的properties實例
* @return 映射後的HashMap容器
*/
public static HashMap<String, Object> newInstance(Properties properties) {
HashMap<String, Object> hashMap = new HashMap<>();
properties.forEach((beanName, beanInstance) -> {
try {
Class<?> klass = Class.forName((String) beanInstance);
Object newBeanInstance = klass.getConstructor().newInstance();
hashMap.put((String) beanName, newBeanInstance);
} catch (Exception e) {
throw new RuntimeException();
}
});
return hashMap;
}
複製代碼
/**
* 爲帶有@Autowired標籤的成員變量設置依賴關係
*
* @param beanName null
* @param beanInstance 被依賴的類的全限定類名
* @param beans 類與類名之間的映射關係
*/
@SuppressWarnings("unused")
public static void dependencyInstance(String beanName, Object beanInstance, HashMap<String, Object> beans) {
List<Field> fields = Stream.of(beanInstance.getClass().getDeclaredFields())
.filter(field -> field.getAnnotation(Autowired.class) != null)
.collect(Collectors.toList());
fields.forEach(field -> {
String filedName = field.getName();
Object filedInstance = beans.get(filedName);
field.setAccessible(true);
try {
//爲beanInstance對象設置依賴關係
field.set(beanInstance, filedInstance);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
});
}
複製代碼
// 啓動該容器
public void start() {
Properties properties = getAndLoadProperties();
hashMap = newInstance(properties);
hashMap.forEach((name, instance) -> {
dependencyInstance(name, instance, hashMap);
});
}
// 從容器中獲取一個bean
public Object getBean(String beanName) {
return hashMap.get(beanName);
}
複製代碼
public class MyIoCContainer {
private HashMap<String, Object> hashMap;
public static void main(String[] args) {
MyIoCContainer container = new MyIoCContainer();
container.start();
OrderService orderService = (OrderService) container.getBean("orderService");
orderService.createOrder();
}
複製代碼
運行結果:
* A BeanDefinition describes a bean instance, which has property values,
* constructor argument values, and further information supplied by
* concrete implementations.
複製代碼
根據描述信息實現BeanDefinition的載入和解析,最後一樣也是Bean的實例化跟依賴注入了。