jdk代理與cglib代理

1. jdk靜態代理

  jdk靜態代理主要使用硬編碼實現.他經過對在代理類中持有委託類的引用,來打到在委託類方法執行前和執行後進行處理,實現簡單,容易理解.java

  代碼以下:app

  1.業務邏輯接口框架

1 package jdkStaticProxy;
2 
3 public interface Service {
4 
5     public void doService();
6 
7 }

  2.業務邏輯實現類ide

1 package jdkStaticProxy;
2 
3 public class ServiceImpl implements Service {
4 
5     @Override
6     public void doService() {
7         System.out.println("this is doService method");
8     }
9 }

  3.代理類測試

 1 package jdkStaticProxy;
 2 
 3 public class ServiceProxy implements Service {
 4 
 5     private Service service;
 6 
 7     public ServiceProxy(Service service) {
 8         this.service = service;
 9     }
10 
11     @Override
12     public void doService() {
13         System.out.println("there is before method");//前置處理方法
14         service.doService();//業務邏輯方法
15         System.out.println("there is after method");//後置處理方法
16     }
17 }

  在代理類中持有一個委託類的應用,以達到在代理類中進行相關處理.this

  4.測試類編碼

 1 package jdkStaticProxy;
 2 
 3 public class Main {
 4 
 5     public static void main(String[] args) {
 6         Service service=new ServiceImpl();
 7         Service serviceProxy=new ServiceProxy(service);
 8         serviceProxy.doService();
 9     }
10 
11 }

  以上就是jdk靜態代理,很容易理解,可是他的問題也顯而易見----dk靜態代理由於是硬編碼實現,因此可能會存在大量的重複代碼.加入咱們的service有10個方法,那麼咱們的代理類中就必須有10個對應的代理方法,這樣的工做量是很是大.spa

2. jdk動態代理

  jdk動態代理主要使用反射實現.要使用jdk代理必須實現一個接口,緣由是jdk代理是用代理類替換委託類進行方法調用,爲了讓代理可以完成替換,就必須實現一個接口,這樣jdk就能生成對應的代理類.代理類的生成主要經過一個Proxy工廠生成,代理類的方法經過調用一個InvocationHandler接口的invoke方法執行..net

  代碼以下:代理

  1.業務邏輯接口

    同靜態代理

  2.業務邏輯實現類

    同靜態代理

  3.InvocationHandler

 1 package jdkDynamicProxy;
 2 
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.Method;
 5 
 6 public class MyInvocationHandler implements InvocationHandler {
 7 
 8     private Object target;
 9 
1011 
12     public MyInvocationHandler(Object target) {
13         this.target = target;
14        15     }
16 
17     @Override
18     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
19 
20         System.out.println("there is before method");
21 
22         method.invoke(target,args);
23 
24         System.out.println("there is after method");
25 
26         return null;
27     }
28 
29 }

    從代碼裏面能夠看出來,代理類持有委託類的引用.委託類的方法是經過反射來進行調用的.method是委託類的方法.

  4.測試類

package jdkDynamicProxy;

import java.lang.reflect.Proxy;

public class Main {

    public static void main(String[] args) {
        ServiceImpl service=new ServiceImpl();
        MyInvocationHandler myInvocationHandler=new MyInvocationHandler(service);

        Service service1= (Service) Proxy.newProxyInstance(
                service.getClass().getClassLoader(),//委託類的類加載器
                service.getClass().getInterfaces(),//委託類的接口
                myInvocationHandler);//InvocationHandler

        service1.doService();

        System.out.println("實際類型:"+service1.getClass());
    }
   
}

  Proxy是一個工廠類,調用newProxyInstance生成一個代理類,傳入委託類加載器和委託類的接口是爲了建立一個可以替換委託類的代理類(爲何須要這兩個參數請了解JVM如何判斷兩個類相等),InvocationHandler爲代理類的邏輯方法.代碼中的service1實際類型是com.sun.proxy.$Proxy0.代理類的建立是經過反射建立,有興趣的讀者能夠研究Proxy的源碼,也能夠看這裏

3. cglib動態代理

  cglib是一個開源庫,他不須要委託類實現一個接口,他是經過建立一個繼承委託類的代理類,來進行強化方法,代理類的實現方法經過調用MethodInterceptor的intercept方法.建立代理類主要藉助asm這個java字節碼生成框架.

  代碼以下:

  1.業務邏輯類

    同靜態代理

  2.intercept

 1 package cglibProxy;
 2 
 3 import net.sf.cglib.proxy.MethodInterceptor;
 4 import net.sf.cglib.proxy.MethodProxy;
 5 
 6 import java.lang.reflect.Method;
 7 
 8 public class MyInterceptor implements MethodInterceptor {
 9 
10     @Override
11     public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
12         System.out.println("-----before");
13         methodProxy.invokeSuper(o,objects);//調用父類(業務邏輯)方法
14         System.out.println("-----after");
15         return null;
16     }
17 
18 }

  其中method是委託類的方法,methodProxy是代理類的代理方法.

  3.測試方法

 1 package cglibProxy;
 2 
 3 import net.sf.cglib.proxy.Enhancer;
 4 
 5 public class Main {
 6 
 7     public static void main(String[] args) {
 8 
 9         Enhancer enhancer=new Enhancer();//該類是cglib的字節碼生成器,可以直接生成對應代理類的字節碼
10         enhancer.setSuperclass(Service.class);//繼承委託類(final類不可被繼承)
11         enhancer.setCallback(new MyInterceptor());//設置回調
12         Service service= (Service) enhancer.create();//生成代理對象
13 
14         service.doService();
15         System.out.println("實際類型:"+service.getClass());
16 
17     }
18 }

    代理類對象是由Enhancer類建立的。Enhancer是CGLIB的字節碼加強器,能夠很方便的對類進行拓展.經過設置回調方法和委託類,生成對應代理類的字節碼,而後將代理類加載進來,生成代理對象.

    建立代理類的步驟以下:

      1.生成代理類的二進制字節碼文件

      2.加載二進制字節碼,生成Class對象( 例如使用Class.forName()方法 )

      3.經過反射機制得到實例構造,並建立代理類對象

    cglib原理請看這裏

4. 各代理對比

  1.jdk靜態代理:實現簡單易懂,可是因爲是硬編碼實現,因此可能會出現大量重複代碼.

  2.jdk動態代理:經過反射機制建立代理類以及代理類方法調用,他在建立代理類的效率上會比cglib高,可是在調用方法的效率上比cglib低.

  3.cglib動態代理:經過生成字節碼的方式建立代理類,他在建立代理類的效率上因爲要生成字節碼以及加載類因此比jdk代理低,可是方法執行效率上因爲是直接執行,不須要進行反射因此效率比jdk代理高.

相關文章
相關標籤/搜索