依賴註入的方式(DI)
方式:
- 接口註入;
- setter方法註入;
- 構造方法註入;
接口註入:
public class ClassA { private InterfaceB clzB; public void doSomething() { Ojbect obj = Class.forName(Config.BImplementation).newInstance(); clzB = (InterfaceB)obj; clzB.doIt(); } …… }
解釋一下上述的代碼部分,ClassA依賴於InterfaceB的實現,我們如何獲得InterfaceB的實現實例呢?傳統的方法是在代碼中創建 InterfaceB實現類的實例,並將賦予clzB.這樣一來,ClassA在編譯期即依賴於InterfaceB的實現。為了將調用者與實現者在編譯期分離,於是有了上面的代碼。我們根據預先在配置文件中設定的實現類的類名(Config.BImplementation),動態加載實現類,並通過InterfaceB強制轉型後為ClassA所用,這就是接口註入的一個最原始的雛形。
setter註入:
setter註入模式在實際開發中有非常廣泛的應用,setter方法更加直觀,我們來看一下spring的配置文件:
<!-- 使用spring管理對象的創建,還有對象的依賴關系 --> <bean id="userDao4Mysql" class="com.tgb.spring.dao.UserDao4MysqlImpl"/> <bean id="userDao4Oracle" class="com.tgb.spring.dao.UserDao4OracleImpl"/> <bean id="userManager" class="com.tgb.spring.manager.UserManagerImpl"> <!-- (1)userManager使用了userDao,Ioc是自動創建相應的UserDao實現,都是由容器管理--> <!-- (2)在UserManager中提供構造函數,讓spring將UserDao實現註入(DI)過來 --> <!-- (3)讓spring管理我們對象的創建和依賴關系,必須將依賴關系配置到spring的核心配置文件中 --><property name="userDao" ref="userDao4Oracle"></property> <property name="id" value="123"></property> </bean>
接著我們來看一下,setter表示依賴關系的寫法:
public class UserManagerImpl implements UserManager{ private UserDao userDao; private int id; //使用設值方式賦值 public void setUserDao(UserDao userDao) { this.userDao = userDao; } //使用設值方式賦值 public void setId(int id) { this.userDao = id; } @Override public void addUser(String userName, String password) { userDao.addUser(userName, password); } }
構造器註入:
構造器註入,即通過構造函數完成依賴關系的設定。我們看一下spring的配置文件:
<!-- 使用spring管理對象的創建,還有對象的依賴關系 --> <bean id="userDao4Mysql" class="com.tgb.spring.dao.UserDao4MysqlImpl"/> <bean id="userDao4Oracle" class="com.tgb.spring.dao.UserDao4OracleImpl"/> <bean id="userManager" class="com.tgb.spring.manager.UserManagerImpl"> <!-- (1)userManager使用了userDao,Ioc是自動創建相應的UserDao實現,都是由容器管理--> <!-- (2)在UserManager中提供構造函數,讓spring將UserDao實現註入(DI)過來 --> <!-- (3)讓spring管理我們對象的創建和依賴關系,必須將依賴關系配置到spring的核心配置文件中 --> <constructor-arg ref="userDao4Oracle"/> </bean>
我們再來看一下,構造器表示依賴關系的寫法,代碼如下所示:
public class UserManagerImpl implements UserManager{ private UserDao userDao; //使用構造方式賦值 public UserManagerImpl(UserDao userDao) { this.userDao = userDao; } @Override public void addUser(String userName, String password) { userDao.addUser(userName, password); } }
接口註入<>setter註入<>構造器註入 比較
接口註入:
接口註入模式因為具備侵入性,它要求組件必須與特定的接口相關聯,因此並不被看好,實際使用有限
。
Setter 註入:
對於習慣了傳統 javabean 開發的程序員,通過 setter 方法設定依賴關系更加直觀。如果依賴關系較為復雜,那麽構造子註入模式的構造函數也會相當龐大,而此時設值註入模式則更為簡潔。如果用到了第三方類庫,可能要求我們的組件提供一個默認的構造函數,此時構造子註入模式也不適用。
構造器註入:
在構造期間完成一個完整的、合法的對象。所有依賴關系在構造函數中集中呈現。依賴關系在構造時由容器一次性設定,組件被創建之後一直處於相對“不變”的穩定狀態。只有組件的創建者關心其內部依賴關系,對調用者而言,該依賴關系處於“黑盒”之中。
依賴註入的方式(DI)