JDK中的Proxy技術實現AOP功能

JDK中的Proxy技術實現AOP功能
 很久沒寫日誌了,今晚重溫了一下傳智播客的視頻,動手使用JDK中的Proxy技術實現AOP功能。
       首先是準備一個接口PersonService及其實現類PersonServiceImpl。

       PersonService:
       public interface PersonService {
           public String getPersonName(Integer personid);
           public void save(String name);
           public void update(String name, Integer personid);
       }

       PersonServiceImpl
       import com.foreveross.service.PersonService;
            public class PersonServiceImpl implements PersonService {
           private String user = null;
           public PersonServiceImpl() {
    }
    public PersonServiceImpl(String user) {
         this.user = user;
    }
    public String getPersonName(Integer personid) {
         System.out.println("我是getPersonName方法");
         return "xxx";
    }
    public void save(String name) {
         System.out.println("我是save方法");
    }
    public void update(String name, Integer personid) {
         System.out.println("我是update方法");
    }
    public String getUser() {
         return user;
    }
       
       爲什麼要用到AOP技術呢?試想一下,如果上邊的三個方法,要通過權限驗證才能使用的話,那麼要在每個方法裏面都加上“if() {}"來判斷嗎?沒錯,這是可行的,但這裏僅針對一個類,如果是N個類呢?大家可能想到,攔截器,但如果不是web項目呢?
       原理圖如下:
            *******************************************************************
            **    客戶端————>代理對象————>目標對象    **
            ******************************************************************* 
       客戶端要調用目標對象之前,先要通過代理對象,再調用目標對象,代理對象實現了目標對象的所有方法。
       JDK中的Proxy技術實現AOP功能 - 彩筆 - 彩筆
        上圖的代碼使用JDK中的Proxy技術實現AOP功能。當我們要調用目標對象PersonServiceImpl的時候,先要通過JDKProxyFactory的createProxyInstance創建代理對象,這個代理對象會執行invoke的方法,裏面判斷是否有權限,有的話,再通過method.invoke,執行目標對象的方法。

       public class AOPTest {
   public static void main(String[] args) {
JDKProxyFactory factory = new JDKProxyFactory();
PersonService service = (PersonService)factory.createProxyInstance(new PersonServiceImpl("abc"));
service.save("john");
    }
       }
       
       上面的測試方法表明,如果傳入了user,即user不爲空,那麼它就有權限執行save方法,打印出“我是save方法”,如果不傳入user,即PersonService service = (PersonService)factory.createProxyInstance(new PersonServiceImpl());,那麼,在代理對象的invoke方法中判斷出沒權限,不會掃行目標對象的save方法,所以沒任何的輸出。


/**
 * 第一個參數爲目標代理加載器
Object o=   Proxy.newProxyInstance(AppTest.class.getClassLoader(),
 A.class.getInterfaces(), new InvocationHandler() {
     B a =   new A();
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
 
return   method.invoke(a, args);
}
});
   ((B)o).a() ;
    */


知識補充:

jvm在初期是將.java文件,編譯成.class文件,當程序運行的時候,Java 虛擬機就將編譯生成的 . class 文件按照需求和一定的規則加載進內存,組織成爲一個完整的 Java 應用程序,jvm會把每個單獨的類和接口編譯成一個單獨的.class文件,這些文件對於 Java 運行環境來說就是一個個可以動態加載的單元。我們可以在不重新編譯其它代碼的情況下,只編譯需要修改的單元,並把修改文件編譯後的 . class 文件放到 Java 的路徑當中, 等到下次該 Java 虛擬機器重新激活時,這個邏輯上的 Java 應用程序就會因爲加載了新修改的 .class 文件,自己的功能也做了更新,這就是 Java 的動態性。 
1. 預先加載與依需求加載 
Java 運行所需要的基本類採用預先加載,的方法全部加載要內存當中,因爲這些單元在 Java 程序運行的過程當中經常要使用的,主要包括 JRE 的 rt.jar 文件裏面所有的 .class 文件。 
我們在程序中需要使用自己定義的類的時候就要使用依需求加載方法。 

2. 隱式加載和顯示加載 
程序中用 new 關鍵字來定義一個實例變量, JRE 在執行到 new 關鍵字的時候就會把對應的實例類加載進入內存,用的也很多, JRE 系統在後臺自動的幫助用戶加載,減少了用戶的工作量,也增加了系統的安全性和程序的可讀性。 
程序員自己寫程序把需要的類加載到內存當中(顯示加載) 
Class c = Class.forName("TestClass"); 
  TestClass object = (TestClass)c.newInstance
 
我們通過 Class 類的 forName (String s) 方法把自定義類 TestClass 加載進來,並通過 newInstance ()方法把實例初始化 
Test test = new Test();//Test 類爲自定義的一個測試類; 

ClassLoader cl = test. getClass().getClassLoader(); 

  // 獲取 test 的類裝載器; 

Class c = Class.forName("TestClass", true, cl); 

    因爲一個類要加載就必需要有加載器,這裏我們是通過獲取加載 Test 類的加載器 cl 當作加載 TestClass 的類加載器來實現加載的。 



   3. 自定義類加載機制 
URL url = new URL("file:/d:/test/lib/"); 

  URLClassLoader urlCL = new URLClassLoader(new URL[]{url}); 

  Class c = urlCL.loadClass("TestClassA"); 

  TestClassA object = (TestClassA)c.newInstance(); 

  object.method(); 



首先定義 URL 指定類加載器從何處加載類, URL 可以指向網際網絡上的任何位置,也可以指向我們計算機裏的文件系統 ( 包含 JAR 文件 ) .上述範例當中我們從 file:/d:/test/lib/ 處尋找類;然後定義 URLClassLoader 來加載所需的類,最後即可使用該實例了。 
  4. 類加載器的階層體系 
當執行hllo.class時候,java.exe會自動找到很顯眼的jre位置,接着會在其中找到jvm.dll,(在jdk和jre中都有jvm)有了.dll文件之後激活jvm加載動態庫,jvm活後,先做一些初始化的動作,比如說讀取系統參數等。 
  然後,一旦初始化動作完成之後,就會產生第一個類加載器―― Bootstrap Loader (靴帶機制,就是繫上鞋帶就要走路了), Bootstrap Loader 是由 C++ 所撰寫而成,這個 Bootstrap Loader 所做的初始工作中,除了一些基本的初始化動作之外,最重要的就是加載 Launcher.java 之中的 ExtClassLoader ,並設定其 Parent 爲 null ,代表其父加載器爲 BootstrapLoader .然後 Bootstrap Loader 再要求加載 Launcher.java 之中的 AppClassLoader ,並設定其 Parent 爲之前產生的 ExtClassLoader 實體。這兩個加載器都是以靜態類的形式存在的。這裏要請大家注意的是, Launcher$ExtClassLoader.class 與 Launcher$AppClassLoader.class 都是由 Bootstrap Loader 所加載,所以 Parent 和由哪個類加載器加載沒有關係。 

這三個加載器就構成我們的 Java 類加載體系。他們分別從以下的路徑尋找程序所需要的類: 

BootstrapLoader : sun.boot.class.path 

ExtClassLoader: java.ext.dirs 

AppClassLoader: java.class.path 

    這三個系統參量可以通過 System.getProperty() 函數得到具體對應的路徑。大家可以自己編程實現查看具體的路徑。  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章