本身動手編寫spring IOC源碼

前言:對於spring IOC概念不是很瞭解的朋友能夠閱讀我上一篇博客——輕鬆理解spring IOC(這兩篇博客也是因爲個人我的緣由致使如今才發佈,慚愧啊)。經過這篇博客的理解以後,相信你們會對spring的IOC概念會有進一步的理解。接下來我先預覽一下本例中java的類圖關係。html

解析:咱們有一個Master接口,接口中定義了一個WalkDog()遛狗的方法,Hostess是對這個接口的具體實現。而後咱們有一個Dog接口,接口中有一個bark()方法,Labuladuo和Taidi是對其的實現。最後咱們的程序入口Client類調用Hostess對象的WalkDog方法。java

需求:Hostess對象遛狗須要一個狗對象,目前咱們的類中有兩個符合需求的對象,咱們只要在配置文件中進行相關配置即可以指定咱們的Hostess對象調用的是哪個具體的Dog對象。算法

 1 public static void main(String[] args) {
 2         ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
 3         Master master = (Master)context.getBean("hostess");
 4         
 5         System.out.println();
 6         System.out.println();
 7         System.out.println();
 8         System.out.println("***********************************");
 9         master.WalkDog();
10     }

解析:從main方法的前兩句原spring的代碼中咱們能夠猜測,spring框架中必定是定義了ApplicationContext這個接口,而且接口中定義了一個getBean()的方法,而ClassPathXmlApplicationContext類確定是對其的實現。既然是咱們本身動手寫spring框架,咱們把這個接口和類實現了也就能夠了。spring

接口 ApplicationContext 安全

1 public interface ApplicationContext {
2     public Object getBean(String beanid);
3 }

實現類 ClassPathXmlApplicationContextapp

 1 package com;
 2 
 3 import java.io.File;
 4 import java.lang.reflect.Method;
 5 
 6 import org.dom4j.Document;
 7 import org.dom4j.DocumentException;
 8 import org.dom4j.Element;
 9 import org.dom4j.Node;
10 import org.dom4j.io.SAXReader;
11 
12 public class ClassPathXmlApplicationContext implements ApplicationContext {
13 
14     private String fileName;
15     
16     public ClassPathXmlApplicationContext(String fileName){
17         this.fileName = fileName;
18     }
19     
20     @Override
21     public Object getBean(String beanid) {
22         //獲取本類的當前目錄
23         String currentPath = this.getClass().getResource("").getPath().toString();
24         
25         SAXReader reader = new SAXReader();//DOM4J解釋器
26         Document doc = null;//xml文檔自己
27         Object obj = null;//目標表建立出來的實例
28         try {
29             doc = reader.read(  new File(currentPath+fileName)  );
30             String xpath = "/beans/bean[@id='"+beanid+"']";
31             Element beanNode = (Element) doc.selectSingleNode(xpath);
32             String className = beanNode.attributeValue("class");
33             obj = Class.forName(className).newInstance();
34             
35             Element propertyNode = (Element) beanNode.selectSingleNode("property");
36             
37             if(propertyNode!=null){
38                 System.out.println("當前bean有屬性須要注入");
39                 
40                 String propertyName = propertyNode.attributeValue("name");
41                 System.out.println("當前bean須要注入的屬性爲"+propertyName);
42                 
43                 //拼接出注入方法
44                 String setMethod = "set"+(propertyName.substring(0, 1)).toUpperCase()+propertyName.substring(1,propertyName.length());
45                 System.out.println("自動調用注入方法"+setMethod);
46                 
47                 String set_object_name = propertyNode.attributeValue("ref");
48                 System.out.println("須要注入的對象名"+set_object_name);
49                 
50                 Object di_object = getBean(set_object_name);
51                 System.out.println("注入的對象實例"+di_object);
52                 
53                 Method []methods = obj.getClass().getMethods();
54                 
55                 for (Method m : methods) {
56                     if(setMethod.equals(m.getName())  ) {
57                         m.invoke(obj, di_object);
58                         break;
59                     }
60                 }
61                 
62             }else{
63                 System.out.println("當前bean沒有屬性,無需注入直接結束");
64             }
65             
66         } catch (Exception e) {
67             e.printStackTrace();
68         }
69         
70         
71         return obj;
72     }
73 
74 }

配置文件 applicationContext.xml框架

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans>
 3     <bean id="hostess" class="com.Hostess">
 4         <property name="dog" ref="Taidi_dog"></property>
 5     </bean>
 6     
 7     <bean id="Taidi_dog" class="com.Taidi"></bean>
 8     
 9     <bean id="Labuladuo_dog" class="com.Labuladuo"></bean>
10 </beans>

解析:① 咱們的applicationContext.xml文件主要是配置咱們的java bean。這裏咱們本身寫一份這樣的文件通知咱們本身的框架有哪些對象須要注入。dom

② 接口 ApplicationContext 這裏我只是定義了一個方法就很少解釋了。ide

③ 實現類 ClassPathXmlApplicationContext 主要是解析咱們的xml文件而後構造實例的一個類。解析xml文件咱們主要使用的是dom4j,獲取各個節點和節點屬性與屬性值。建立對象則是經過反射的方式構造對象 [obj = Class.forName(className).newInstance();]。 在判斷一個對象是否有屬性須要注入則是使用遞歸算法對其一一注入。this

最後: 咱們來看一下運行結果

小結:咱們本身手寫的框架天然沒有spring框架嚴謹,安全(否則它早倒閉了),不過spring的原理咱們本身的也是大同小異的。經過源碼級別的解讀,相信你們已經能夠熟練掌握IOC原理。

相關文章
相關標籤/搜索