首頁  >  文章  >  Java  >  java代理模式介紹

java代理模式介紹

王林
王林轉載
2021-01-27 09:50:442898瀏覽

java代理模式介紹

我們先來介紹下什麼是代理。

(學習影片分享:java影片教學

代理程式是一種設計模式,它的核心思想,是將對目標的存取轉移到代理物件上。這樣做的好處就是,目標物件在不改變程式碼的情況下,可以透過代理物件加上一些額外的功能。這是一種程式設計思想,在不改變原有程式碼的情況下,透過代理程式增加一些擴充功能。

代理程式如圖所示,使用者存取代理對象,代理對象透過存取目標對象,來達到使用者存取目標對象的目的,

java代理模式介紹

##代理程式模式包含三個角色:

ISubject:介面對象,該介面是對象和它的代理共用的介面。

TargetSubject:目標對象,是實作抽象主題介面的類別。

Proxy:代理角色,內部含有對目標物件TargetSubject的引用,因此可以操作真實物件。代理物件提供與目標物件相同的接口,以便在任何時刻都能取代目標物件。同時,代理物件可以在執行目標物件操作時,附加其他的操作,相當於對真實物件進行封裝。

常見的代理模式分為靜態代理和動態代理,動態代理在Java中的實作分為JDK動態代理和cglib代理。

靜態代理

在之前已經說過,在代理模式中有三個角色,一是目標接口,二是目標對象,三是代理對象。

現在以具體程式碼來實現,首先是目標接口如下:

 public interface IBlogService {

    void writeBlog();
}

目標對象實現了目標接口,程式碼如下:

public class BlogService implements IBlogService {

    @Override
    public void writeBlog() {
        System.out.println("i'm writing...");
    }
}

靜態代理對象,透過建構方法獲取到目標對象,並實現了目標接口,在目標接口的方法裡調用了目標對象的方法,代碼如下:

public class BlogStaticProxy implements IBlogService{
    private IBlogService blogService;

    public BlogStaticProxy(IBlogService blogService) {
        this.blogService = blogService;
    }

    @Override
    public void writeBlog() {
        System.out.println("start writing...");
        blogService.writeBlog();
        System.out.println("end writing...");
    }
}

靜態代理對象,通過構造方法獲取到目標對象,並實現了目標接口,在目標接口的方法裡呼叫了目標對象的方法,代碼如下:

public class BlogStaticProxy implements IBlogService{
    private IBlogService blogService;

    public BlogStaticProxy(IBlogService blogService) {
        this.blogService = blogService;
    }

    @Override
    public void writeBlog() {
        System.out.println("start writing...");
        blogService.writeBlog();
        System.out.println("end writing...");
    }
}

測試:

public class TestStaticProxy {

    public static void main(String[] args) {
        IBlogService target = new BlogService();
        BlogStaticProxy proxy = new BlogStaticProxy(target);
        proxy.write();
    }
}
start writing…
i’m writing…
end writing…

靜態代理,在不修改目標對象的情況下,可以通過代理對象做額外的擴充功能。但靜態方法不是很靈活,如果目標介面的程式碼修改,目標物件和代理物件都需要修改。

動態代理在一定程度上避免這種情況,動態代理不需要代理對象實現目標接口,並且上在java 虛擬機的內存中動態的生成代理對象

Jdk動態對象

Jdk的動態代理由Proxy這個類別來生成,它有三個參數:

ClassLoader loader,:指定目前目標物件使用類別載入器,取得載入器的方法是固定的

Class>[] interfaces,:目標物件實現的介面的類型,使用泛型方式確認類型

#InvocationHandler h:事件處理,執行目標物件的方法時,會觸發事件處理器的方法,會把目前執行目標物件的方法作為參數傳入

 public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {

    }

Jdk的動態代理程式碼如下:

 public class JdkBlogProxyFactory {

    private Object target;

    public JdkBlogProxyFactory(Object target) {
        this.target = target;
    }

    public Object newInstance() {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                (proxy, method, args) -> {
                    System.out.println("start writing");
                    Object o = method.invoke(target, args);
                    System.out.println("end writing");
                    return o;
                });
    }
}

測試類別:

public class TestJdkProxy {
    public static void main(String[] args) {

        IBlogService target = new BlogService();

        System.out.println(target.getClass());

        // 给目标对象,创建代理对象
        IBlogService proxy = (IBlogService) new JdkBlogProxyFactory(target).newInstance();
        // class $Proxy0   内存中动态生成的代理对象
        System.out.println(proxy.getClass());

        // 执行方法   【代理对象】
        proxy.writeBlog();
    }
}

控制台列印如下:

class com.forezp.proxy.BlogService
class com.sun.proxy.$Proxy0
start writing
i&#39;m writing...
end writing

CGLib動態代理

CGLib採用了非常底層的字節碼技術,其原理是透過字節碼技術為一個類別建立子類,並在子類中採用方法攔截的技術攔截所有父類別方法的調用,順勢織入橫切邏輯。

CglibBlogFactory代理工廠類別如下:

public class CglibBlogFactory implements MethodInterceptor {

    private Object target;

    public CglibBlogFactory(Object target) {
        this.target = target;
    }

    //给目标对象创建一个代理对象
    public Object getProxyInstance() {
        //1.工具类
        Enhancer en = new Enhancer();
        //2.设置父类
        en.setSuperclass(target.getClass());
        //3.设置回调函数
        en.setCallback(this);
        //4.创建子类(代理对象)
        return en.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("start writing...");
        //执行目标对象的方法
        Object returnValue = method.invoke(target, objects);
        System.out.println("end writing...");
        return returnValue;
    }
}

測試類別:

public class TestCglib {

    public static void main(String[] args) {
        IBlogService target = new BlogService();
        //代理对象
        IBlogService proxy = (IBlogService) new CglibBlogFactory(target).getProxyInstance();
        //执行代理对象的方法
        proxy.writeBlog();
    }
}

運行程序,控制台列印:

start writing...
i&#39;m writing...
end writing...

相關推薦:

java入門教學

以上是java代理模式介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:juejin.im。如有侵權,請聯絡admin@php.cn刪除