Spring依賴注入原理


    接觸過spring 的同學應該都知道依賴注入,依賴注入又稱控制反轉,其內涵就是,將創建某個bean的控制權力,由原來需要引用這個bean的bean轉移(反轉)到外部的spring IOC容器,由IOC容器統一創建,並且注入到需要引用的bean中去。 那么spring是怎么做到依賴注入的,我們來看看spring是怎么做的吧!

    其實,spring的本質是一個工廠(beanFactory)或者說bean容器,它按照我們的要求,生產我們需要的各種各樣的bean,提供給我們使用。只是在生產bean的過程中,需要解決bean之間的依賴問題,才引入了依賴注入(DI)這種技術。也就是說依賴注入是beanFactory生產bean時為了解決bean之間的依賴的一種技術而已。但是,我們一般都不直接用BeanFactory,而是用它的實現類ApplicationContext,這個類會自動解析我們配置的applicationContext.xml,然后根據我們配置的bean來new對象,將new好的對象放進一個Map中,鍵就是我們bean的id,值就是new的對象。

    我們來看一下beanFactory的代碼:

 1 package org.springframework.beans.factory;
 2 
 3 public interface BeanFactory {
 4     String FACTORY_BEAN_PREFIX = "&";
 5 
 6     Object getBean(String var1) throws BeansException;
 7 
 8     <T> T getBean(String var1, Class<T> var2) throws BeansException;
 9 
10     <T> T getBean(Class<T> var1) throws BeansException;
11 
12     Object getBean(String var1, Object... var2) throws BeansException;
13 
14     <T> T getBean(Class<T> var1, Object... var2) throws BeansException;
15 
16      ...
17 }

 

beanFactory是一個接口,其中定義了各種getBean()方法,我們可以看到返回的是一個object對象,因此通過上下文對象ApplicationContext對象拿到的對象都必須通過強轉能變成指定的類型的對象。

 

我們再來模擬ClassPathXmlApplicationContext的是怎么拿到bean的:

 1 package com.spring.Context;
 2 
 3 import java.util.HashMap;
 4 import java.util.List;
 5 import java.util.Map;
 6 
 7 import org.dom4j.Document;
 8 import org.dom4j.DocumentException;
 9 import org.dom4j.Element;
10 import org.dom4j.io.SAXReader;
11 
12 
13 public class ClassPathXmlApplicationContext implements BeanFactory {
14     private Map<String, Object> beanMap = new HashMap<String, Object>();   //map的value是object
15     public ClassPathXmlApplicationContext(String fileName) throws Exception{
16         SAXReader reader = new SAXReader();
17         Document document = reader.read(this.getClass().getClassLoader().getResourceAsStream(fileName));  //SAX解析對應的xml配置文件
18         List<Element> elements = document.selectNodes("/beans/bean");
19         for (Element e : elements) {
20             String id = e.attributeValue("id");
21             String value = e.attributeValue("class");
22             Object o = Class.forName(value).newInstance();   //利用反射通過類名拿到的類的一個實例對象 23             beanMap.put(id, o);
24         }
25     }
26     
27     public Object getBean(String id) {
28         return beanMap.get(id);
29     }
30 
31 }

 

我們可以發現,通過spring  getBean()拿到的對象實例,都是通過讀取applicationContext.xml文件,再通過反射拿到的類的實例對象。

因此,spring注入的對象必須可以實例化,也就是說,接口和抽象類是不能通過spring實現注入的,因為兩者都不能實例化。

這就讓人很不能理解了,因為在做spring-mybatis整合的時候,我們有一個常見的做法就是在service層通過注解注入dao層接口,在這里不是可以注入接口嗎?為什么又說spring不能注入接口呢?

其實,這里注入的接口,並不是真正的接口,我們不妨吧這個注入的“接口”打印出來看看,到底是個什么東西:

1 the dao is:  org.apache.ibatis.binding.MapperProxy@33e4ae3b
2 the dao class is : class com.sun.proxy.$Proxy21

輸出顯示,其實注入的並不是接口,而是mybatis中的mapper對象的代理類。

至於這個里面的玄機,還是等下次去探討吧!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM