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是執行緒安全的嗎?使用時應該注意什麼?
Java面試題:細數ThreadLocal大坑,記憶體洩露本可避免
Java面試題:請談談對ThreadLocal的理解?
Java面試題:為什麼HashMap不建議使用物件作為Key?