Spring的IOC(控制反轉)是一種設計模式,它允許開發者將對象的創建和管理交給Spring框架來完成。在Spring中,IOC允許開發者將對象依賴關係從代碼中分離出來,從而使代碼更加靈活、可重用和易於管理。
IoC 全稱Inverse of Control(反向控制或控制反轉)。
在類和類之間存在控制權,控制權指的是對象的創建和使用,比如有類A和類B,我們之前的做法是在A中調用B,那麼控制權就在A中,這樣做的耦合度較高,如果修改了 B,A也要做相應修改。
class A { } class B { // B需要將A的實例new出來,也就是我們說的控制 private A a = new A(); public void use() { System.out.print(a); } }
引入Spring框架後,控制權由 spring 容器來負責。當A想使用B時,需要由 Spirng容器通過配置文件進行注入。這種思想就是IoC(爲了更好的理解,我們可以這樣認爲,對象創建和使用的控制權轉移到了Spring容器,由Spring容器來控制)。
// 說明A自己控制自己,把自己初始化出來,注入給了容器 @Component class A { } class B { // B不需要控制a,直接使用。如果A沒有把自己注入給容器,B就不能使用 @Resource private A a; public void use() { System.out.print(a); } }
實現Spring的IOC(控制反轉)有以下幾種方式:
-
使用@Autowired註解:這是Spring中最常用的實現IOC的方式。通過在需要依賴注入的類上使用@Autowired註解,Spring會自動將依賴對象注入到該類中。
-
使用配置文件:通過在Spring配置文件中定義bean,可以手動創建和管理對象。這種方式適合於需要靈活控制對象創建和生命週期的情況。
-
使用Java配置:通過使用Java配置類,可以更靈活地定義bean和配置對象之間的關係。這種方式適合於需要更細粒度控制的情況。
如何實現一個簡易的IOC功能?
上述是Spring容器簡單的使用IOC功能,如果我們自己想實現一個簡單版的,可以按照以下步驟:
-
定義一個容器類,用於管理對象的創建和注入。
-
實現對象的創建方法,可以使用常見的工廠模式或依賴查找等方式來創建對象。
-
在容器類中定義一個注入方法,用於將對象注入到需要依賴的對象中。
下面是一個簡單的代碼示例,展示瞭如何實現一個簡易的IOC功能:
// 定義容器類 public class ObjectContainer { // 創建對象的方法 public static Object createObject(String className) throws Exception { // 使用反射創建對象 return Class.forName(className).newInstance(); } // 注入對象的方法 public static void injectObject(Object target, String className) throws Exception { // 將對象注入到目標對象中 Field field = target.getClass().getField(className); field.set(target, ObjectContainer.createObject(className)); } } // 使用示例 public class ExampleClass { private Object obj; // 需要注入的對象 public ExampleClass(String className) { try { // 注入對象 ObjectContainer.injectObject(this, className); } catch (Exception e) { e.printStackTrace(); } } public void doSomething() { // 使用對象進行操作 obj.method(); } }
在上面的示例中,我們定義了一個ObjectContainer類,它包含了創建對象和注入對象的方法。在ExampleClass中,我們使用了ObjectContainer的注入方法將對象注入到目標對象中。使用時只需要傳入對象的類名即可。
請注意,上述示例只是一個簡單的實現,沒有考慮一些複雜的場景,例如循環依賴、類型轉換等問題。在實際開發中,需要根據具體的需求和場景進行適當的調整和優化。
使用IOC有哪些好處?
①、使用者不用關心引用Bean的實現細節,譬如對於B b = new A(c,d,e,f);來說,如果B要使用A,那還要 把c,d,e,f侈個類全都感知一遍,這顯然是非常麻煩且不合理的。
②、不用創建多個相同的bean導致浪費,仍然是:
A b = new A(); A c = new A();
如果B和C都引用了A,那麼B和C就可能new兩個A實例,實際上,我們只需要一個就好了。
③、Bean的修改使用方無需感知。同樣是上面的例子,假如說Bean A需要修改,如果沒有IOC的話,所有引用到A的其他Bean都需要感知這個邏輯,並且做對應的修改。但是如果使用了IOC,其他Bean就完全不用感知到。
往期面試題:
Java面試題:SimpleDateFormat是線程安全的嗎?使用時應該注意什麼?