手寫簡易springIOC
springIOC的特點(diǎn)
- spring ioc强衡,spring容器形葬,根據(jù)xml配置合呐,或者是你的注解,去實(shí)例化你的一些bean對象笙以,然后根據(jù)xml配置或者注解淌实,去對bean對象之間的引用關(guān)系,去進(jìn)行依賴注入猖腕,某個(gè)bean依賴了另外一個(gè)bean
- 底層核心技術(shù)拆祈、反射技術(shù),他會通過反射的技術(shù)倘感,直接根據(jù)你的類去自己構(gòu)建對應(yīng)的對象出來放坏,用的就是反射技術(shù)
- spring ioc,系統(tǒng)的類與類之間徹底的解耦合
我的springIOC的目錄結(jié)構(gòu)
1602314613377.jpg
其中我們主要使用的只有MyIocConainer侠仇、OrderDao轻姿、OrderService、UserDao逻炊、XmlPath2Bean和配置文件spring-ioc-my.xml
手寫springIOC源碼
首先是spring-ioc-my.xml 配置文件互亮,配置好容器初始化需要加載的bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 創(chuàng)建方式1:空參構(gòu)造創(chuàng)建 -->
<bean id="orderDao" class="springioc.OrderDao"/>
<bean id="userDao" class="springioc.UserDao"/>
<bean id="orderService" class="springioc.OrderService"/>
</beans>
解析xml的工具類
/**
* @Classname XmlPath2Bean
* @Description TODO
* @Date 2020/10/10 2:27 PM
* @Author by pengasan
*/
public class XmlPath2Bean {
private String xmlPath;
public XmlPath2Bean(String xmlPath) {
this.xmlPath = xmlPath;
}
/**
* 讀取xml文件
* @param
* @return java.util.List<org.dom4j.Element>
* @date 2020/10/6 2:00 PM
* @auther lixin
*/
public List<Element> readXML() throws DocumentException {
SAXReader saxReader = new SAXReader();
// 1.解析xml文件
Document document = saxReader.read(getResourceAsStream(xmlPath));
// 讀取跟節(jié)點(diǎn)
Element rootElement = document.getRootElement();
// 獲取下面的子節(jié)點(diǎn)
List<Element> elements = rootElement.elements();
return elements;
}
/**
* 獲取當(dāng)前上下文路徑
* @param xmlPath
* @return
*/
public InputStream getResourceAsStream(String xmlPath) {
return this.getClass().getClassLoader().getResourceAsStream(xmlPath);
}
}
手寫的容器類
public class MyIocContainer {
// 定義一個(gè)容器! 存放 bean 的名字到 bean 實(shí)例對象的映射
private Map<String, Object> container = new HashMap<>();
/**
* 啟動(dòng)容器
* @param
* @return void
* @date 2020/10/10 2:22 PM
* @auther lixin
*/
public void start(String xmlPath) throws DocumentException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
// bean的初始化
XmlPath2Bean context = new XmlPath2Bean(xmlPath);
//從xml讀取配置文件
List<Element> list = context.readXML();
for (Element element :list ) {
String key = element.attributeValue("id");
String classPath = element.attributeValue("class");
//利用反射拿到clazz
Class clazz = Class.forName(classPath);
//創(chuàng)建單利bean對象
Object beanInstance = clazz.getConstructor().newInstance();
//放入ioc容器
container.put(key, beanInstance);
}
//遍歷container注入每個(gè)bean的依賴
//stream
container.forEach((beanName,beanInstance) -> dePendencyInject(beanInstance));
//傳統(tǒng)方式便于理解
container.forEach((beanName,beanInstance) -> dePendencyInject2(beanInstance));
}
/**
* 注入依賴 stream的方式
* @param beanInstance
* @return void
* @date 2020/10/10 2:43 PM
* @auther lixin
*/
private void dePendencyInject(Object beanInstance) {
// 拿到帶有 @AutoWired 注解的 fields
List<Field> fieldsToBeAutoWired = Stream.of(beanInstance.getClass().getDeclaredFields())
.filter(field -> field.getAnnotation(Autowired.class) != null)
.collect(Collectors.toList());
// 為當(dāng)前 bean 對象的需要依賴的字段注入依賴(設(shè)置字段值)
fieldsToBeAutoWired.forEach(field -> {
// 加了 @AutoWired 的字段名即是所要依賴的 bean 的名字
String fieldName = field.getName();
Object dependencyBeanInstance = container.get(fieldName); // 所依賴的 bean 實(shí)例
try {
// 設(shè)置為 true 用來壓制針對被反射對象的訪問檢查
field.setAccessible(true);
// 從而可以在這里設(shè)置當(dāng)前 bean 的私有字段
field.set(beanInstance, dependencyBeanInstance);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
});
}
/**
* 注入依賴 傳統(tǒng)方式
* @param beanInstance
* @return void
* @date 2020/10/10 2:43 PM
* @auther lixin
*/
private void dePendencyInject2(Object beanInstance) {
//創(chuàng)建一個(gè)list
List<Field> fieldsToBeAutoWired = new ArrayList<>();
//拿到所有屬性
Field[] listField = beanInstance.getClass().getDeclaredFields();
for (Field field : listField) {
// 找到帶有Autowired注解的屬性
if (field.getAnnotation(Autowired.class) != null){
//放入list
fieldsToBeAutoWired.add(field);
}
}
// 為當(dāng)前 bean 對象的需要依賴的字段注入依賴(設(shè)置字段值)
for (Field field : fieldsToBeAutoWired) {
// 加了 @AutoWired 的字段名即是所要依賴的 bean 的名字
String fieldName = field.getName();
// 去容器中找到所需要的bean
Object dependencyBeanInstance = container.get(fieldName);
try {
// 設(shè)置為 true 用來壓制針對被反射對象的訪問檢查
field.setAccessible(true);
// 從而可以在這里設(shè)置當(dāng)前 bean 的私有字段
field.set(beanInstance, dependencyBeanInstance);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
/**
* 根據(jù)名稱獲取bean
* @param name
* @return java.lang.Object
* @date 2020/10/10 3:15 PM
* @auther lixin
*/
public Object getBean(String name){
return container.get(name);
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, DocumentException, InvocationTargetException, ClassNotFoundException {
MyIocContainer context = new MyIocContainer();
context.start("spring-ioc-my.xml");
}
}
不太重要的orderService
1602315055571.jpg