簡單jdk動態代理


在學習動態代理之前,最好先去理解靜態代理,如果未曾了解過靜態代理,建議先理解靜態代理。

在靜態代理中,你需要自己去寫一個代理類和被代理類實現相同的接口,在代理類中寫上代理邏輯,確定要代理哪些方法,如果有新的變動需要修改源代碼,重新編譯部署,非常不方便,可以看看下面的例子:

我們已經通過靜態代理的方實現了再登陸之前打印日志的能,但是現在有新的需求,A1類除了登陸,還要實現吃飯的功能,吃飯前后也要打印日志,

為了實現功能,於是做了一些修改,下圖中紅色的部分就是改動的部分:

 

  

至此,靜態代理的缺點十分明顯了,因為代理類是在編譯之前就寫好的,而且代理類和被代理類關系太緊,只要被代理類的邏輯變了,或者實現的接口變了,代理也得跟着變,直接修程序原意味着要重新測試,部署,難以維護;問題之二:代理中的重復代碼(打印日志部分)是無法通過縱向抽取(繼承)來消除的,也就有了橫向抽取(橫切)來解決,於是就AOP(Aspect Oriented Progranming),那又是另外一個故事了。

試想,如果在編譯之前不能用確定代理類是哪一種類型,只有在編譯的時候根據傳入接口,代理邏輯,需要代理的類來生成代理類,不用我們自己寫代理類,也就沒有代碼重復和大面積修改的行為,這就是jdk的動態代理機制,整體架構如下.                                   

tip :    1)依賴關系:A類的某個方法的入參是B類對象,這是一種臨時的關系          2)關聯關系:A類的成員變量中包含B類對象

通過上面這種組織關系,調用者只需要面對JDK自動生成的代理類,代理類會去完成業具體的業務邏輯和代理邏輯,不用我們自己編寫代理類,自然也就不會為接口改變而犯難了。想要使用jdk的動態代理,首先被代理類你的寫出來,然后你要解決代理邏輯寫在那個類的問題。

為了解決第一個問題:需要下面兩個類:

//JDK動態代理只能代理有接口的類,所以和靜態代理一樣,需要有接口,和對應的實現類
public interface UserService { void login(String userName,String password); void register(); }

/**
 * 被代理的對象  也是接口的實現類
*/
public class UserServiceImpl implements UserService,UserLife{

@Override

public void login(String userName, String password) {

System.out.println(userName + " login");

}

@Override
public void register() {
System.out.println("register().....");
}
}

 第二步 :代理邏輯寫在什么地方,按照jdk動態代理的實現規則,代理邏輯要寫在一個實現 了 java.lang.reflect.InvocationHandler接口的類中,於是就有了下面的代碼

public class UserServiceInvocationHandler implements InvocationHandler {

    /**
     * 要被代理的目標對象
     */
    private UserService userService;

    public UserServiceInvocationHandler(UserService userService){
        this.userService = userService;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("do something before 打印日志....");
       //調用被代理對象的業務處理方法
        Object result = method.invoke(userService,args);
        System.out.println("do something before 打印日志....");
        return result;
    }
}

 至此,我們要寫的代碼已經寫完了,動態代理類是在運行的時候動態生成的,該如何去調用者動態生成的對象去完成特定功能呢?具體代碼如下

public class Test{

    public static void main(String[] args) {
        System.out.println("---------動態代理類-----------");
//讓jvm動態生成代理類 這就是JDK的動態代理 UserService service = (UserService)Proxy.newProxyInstance(Test.class.getClassLoader(), new Class[]{UserService.class, UserLife.class},//被代理類實現的接口 new UserServiceInvocationHandler(new UserServiceImpl()));//代理邏輯 service.login("jack","12345"); System.out.println("-----------------------"); service.register(); System.out.println("動態代理類的名字" + service.getClass().getName()); } }

------------------------------運行結果如下--------------------------

---------動態代理類-----------
do something before 打印日志....
jack login
do something before 打印日志....
-----------------------
do something before 打印日志....
register().....
do something before 打印日志....
動態代理類的名字com.sun.proxy.$Proxy0


 


總結和思考:通過JDK的動態代理機制,我們可以對增強類的功能,在那些需要的方法執行前后加入相應的代理邏輯,但是本文演示的只是最簡單的動態代理方式,也就是默認代理類中的所有方法的都需要被代理,所以被代理的類的每一個方法調用前后都會執行額外操作,如果想要靈活的使用動態代理還需要借助java中的反射機制和注解,就能隨心所欲,只為代理類中特定方法進行代理。 

 


免責聲明!

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



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