1.程序中為什么會用到spring的ioc和aop
2.什么是IOC,AOP,以及使用它們的好處,即詳細回答了第一個問題
3.原理
關於1:
a:我們平常使用對象的時候,一般都是直接使用關鍵字類new一個對象,那這樣有什么壞處呢?其實很顯然的,使用new那么就表示當前模塊已經不知不覺的和 new的對象耦合了,而我們通常都是更高層次的抽象模塊調用底層的實現模塊,這樣也就產生了模塊依賴於具體的實現,這樣與我們JAVA中提倡的面向接口面向抽象編程是相沖突的,而且這樣做也帶來系統的模塊架構問題。很簡單的例子,我們在進行數據庫操作的時候,總是業務層調用DAO層,當然我們的DAO一般 都是會采用接口開發,這在一定程度上滿足了松耦合,使業務邏輯層不依賴於具體的數據庫DAO層。但是我們在使用的時候還是會new一個特定數據庫的DAO 層,這無形中也與特定的數據庫綁定了,雖然我們可以使用抽象工廠模式來獲取DAO實現類,但除非我們一次性把所有數據庫的DAO寫出來,否則在進行數據庫 遷移的時候我們還是得修改DAO工廠類,所以我們就思考新的方法
b:
1 public class Hello implements IHello { 2 3 public void sayHello(String name) { 4 // TODO Auto-generated method stub 5 System.out.println("Hello " + name); 6 } 7 8 }
如上圖,假設我們要在方法的開始和結束處加上一些業務邏輯,大家想到的最直接的方法,就是在方法前面和后面加上一些代碼,如日志,假如不能改變原來的方法了,那你又會想到繼承Hello類,重寫sayHello方法,如下
public class Hello2 extends Hello { public void sayHello(String name) { // TODO Auto-generated method stub sysstem.out.println("方法前的邏輯"); super.sayHello("。。。。。。"); } }
可能你又會想到,組合的方式
public class Hello3 implements IHello { private IHello helloDao = new Hello(); public void sayHello(String name) { // TODO Auto-generated method stub sysstem.out.println("方法前的邏輯"); helloDao .sayHello("。。。。。。"); } }
假設現在要把這個日志功能加入到20個不同方法的前面,可以考慮把那個日志功能抽離出來封裝成一個類的方法,但是那樣還是要組合新建20個類,組合20次,如下
public class LogInterceptor { public void before() { System.out.println("method before"); } } public class Hello3 implements IHello { private IHello helloDao = new Hello(); public void sayHello(String name) { // TODO Auto-generated method stub new LogInterceptor().before(); helloDao .sayHello("。。。。。。"); } } public class hello4 implements 其他接口 {//需要新建類 private IHello qitaDao = new 其他業務類();//需要組合舊的類 public void doHello(String name) { // TODO Auto-generated method stub new LogInterceptor().before(); helloDao .sayHello("。。。。。。"); } }
。。。20次
這樣肯定不可靠。我們想新的思路,可以寫一個配置文件,在每個需要加日志邏輯的里面,例Hello類的所有方法上配上那個日志類的方法,這樣就不用新建20個類,組合20次舊的類,但是問題又來了,程序不會返回你重新組合的那個類(即那個新組合而成的動態類),我們需要思考新的方法
關於2:
IOC:Inversion of Control 控制反轉,也叫(Dependency Injection)依賴注入,上述a的邏輯使用IOC,就是DAO接口的實現不再是業務邏輯層調用工廠類去獲取,而是通過容器(spring)來自動的為我們的業務層設置DAO的實現類,這樣整個過程就反過來,以前是我們業務層主動去獲取DAO,而現在是DAO主動被設置到業務邏輯層中來了,這也就是反轉控制的由來。通過IOC,我們就可以在不修改任何代碼的情況下,無縫的實現數據庫的換庫遷移
AOP:Aspect Oriented Programming 面向切面編程,上述b的邏輯就使用AOP,就可以解決,他幫助我們生成動態的代理類,織入新的業務邏輯,如事務,日志等等
關於3:
IOC原理:

public class UserService{ //private UserDao userDao = new UserDaoImpl(); //讓業務層與數據訪問層耦合在一起,不利用以后模塊的替換. private UserDao userDao_IoC = null; public void setUserDao(UserDao userDao){ this.userDao_IoC = userDao } public void save(User user){ userDao.save(user); } } //原理:反射 public void ObjectgetInstance(String className) throws Exception { Object obj = Class.forName(className).newInstance(); Method[] methods = obj.getClass().getMethods(); for (Method method : methods) { if (method.getName().intern() == "setUserDao") { method.invoke(obj, "換成實現接口類的名稱!"); } } }
AOP原理:下面是jdk實現的動態代理

1 package com.s2sh.intercepetor; 2 3 4 public interface IHello { 5 public void sayHello(String name); 6 7 public void sayGoogBye(String name); 8 } 9 10 11 package com.s2sh.intercepetor; 12 13 public class Hello implements IHello { 14 15 16 public void sayGoogBye(String name) { 17 // TODO Auto-generated method stub 18 System.out.println(name+" GoodBye!"); 19 } 20 21 22 public void sayHello(String name) { 23 // TODO Auto-generated method stub 24 System.out.println("Hello " + name); 25 } 26 27 } 28 29 package com.s2sh.intercepetor; 30 31 32 public class Logger { 33 public static void before() { 34 System.out.println("開始了"); 35 } 36 37 public static void after() { 38 System.out.println("結束了"); 39 } 40 } 41 42 43 44 package com.s2sh.intercepetor; 45 46 import java.lang.reflect.InvocationHandler; 47 import java.lang.reflect.Method; 48 import java.lang.reflect.Proxy; 49 50 51 public class DynaProxyHello implements InvocationHandler { 52 private Object delegate;//被代理的對象 53 54 public DynaProxyHello(Object delegate) { 55 this.delegate = delegate; 56 } 57 public Object invoke(Object proxy, Method method, Object[] args) 58 throws Throwable { 59 // TODO Auto-generated method stub 60 Object result = null; 61 try { 62 // 執行原來的方法之前記錄日志 63 Logger.before(); 64 // JVM通過這條語句執行原來的方法(反射機制) 65 result = method.invoke(this.delegate, args); 66 // 執行原來的方法之后記錄日志 67 Logger.after(); 68 } catch (Exception e) { 69 e.printStackTrace(); 70 } 71 // 返回方法返回值給調用者 72 return result; 73 } 74 75 76 } 77 78 79 package com.s2sh.intercepetor; 80 81 import java.lang.reflect.Proxy; 82 83 public class Test { 84 public static void main(String[] args) { 85 // ①目標業務類 86 IHello target = new Hello(); 87 // ② 將目標業務類和橫切代碼編織到一起 88 DynaProxyHello handler = new DynaProxyHello(target); 89 // 創建代理類 90 IHello proxy = (IHello) Proxy.newProxyInstance( target.getClass().getClassLoader(), //返回目標類的類裝載器,保持兩個類的類裝載器一樣 target.getClass().getInterfaces(), //返回目標類實現的接口,保證組合而成的代理類也實現這些接口 handler//指派誰去處理方法的對象 ); 92 // ④ 操作代理實例 93 proxy.sayHello("張三"); 94 proxy.sayGoogBye("李四"); 95 } 96 }
運行結果:
開始了-- Hello 張三 結束了--
開始了-- 李四 GoodBye! 結束了--