spring - ioc和aop


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原理:

View Code
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實現的動態代理

View Code
 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
! 結束了--

 

 

      

 


免責聲明!

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



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