14.【設計模式.結構型.代理模式】代理模式的的實現

設計模式.結構型.代理模式

一、說明:

代理模式是爲了增強被代理對象(目標對象)的方法,可在不改變目標對象的代碼情況下對其方法進行增強。遵循了開閉原則。spring框架中的AOP就是基於代理模式開發。實現方法相對固定。

二、靜態代理

顯式地描述出具體的目標對象,需要代理對象和目標對象都實現同一個接口。

package com.fatsea.news.pattern.structural;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @Author: Chunhai.Hu
 * @Date: 2021/4/28 16:02
 * @Desc: 代理模式(CGLib動態代理方式)測試
 * 被代理對象不必實現某個接口即可進行代理
 * CGLIB原理:繼承目標對象,重寫目標對象的方法
 */
public class CglibProxyTest {
    public static void main(String[] args) {
        RealPerson target = new RealPerson();
        RealPerson proxy  = new CglibRealPerson(target).createProxy();
        proxy.sayHello("我是CGLib代理的對象");
        proxy.sayHi("小王", "我是最可愛的人");
    }
}

// 代理對象:實現MethodInterceptor接口即可
class CglibRealPerson implements MethodInterceptor {

    private RealPerson target;

    public CglibRealPerson(RealPerson target) {
        this.target = target;
    }

    /**
     * @對外暴露代理對象
     * @return
     */
    public RealPerson createProxy () {
        Enhancer enhancer = new Enhancer();
        // 指定父類
        enhancer.setSuperclass(RealPerson.class);
        // 指定回調方法
        enhancer.setCallback(this);
        // 返回代理對象
        return (RealPerson) enhancer.create();
    }

    private int i = 0;
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("invoke第:" + ++i + "次執行。");
        System.out.println("執行的方法名稱:" + method.getName());

        System.out.println("代理之前執行的方法" + i);
        method.invoke(target, objects);
        System.out.println("代理之後執行的方法" + i);
        return null;
    }
}

// 目標對象:沒有實現任何接口
class RealPerson {
    public void sayHello (String word) {
        System.out.println(word);
    }

    public void sayHi (String name, String word) {
        System.out.println("我是:" + name + "***說:***" + word);
    }
}

三、JDK代理

爲原生的JDK開發包中所包含的代理實現API,需要代理對象和目標對象都實現同一個接口(如下實例中複用了上面目標對象)。

package com.fatsea.news.pattern.structural;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @Author: Chunhai.Hu
 * @Date: 2021/4/28 11:58
 * @Desc: 代理模式(JDK動態代理方式)測試
 * 使用前提:被代理對象必須實現某個接口
 */
public class JdkProxyTest {
    public static void main(String[] args) {
        // 被代理對象(目標對象)
        Subject target = new RealSubject();
        // 被代理對象的調用處理器
        InvocationHandler invocationHandler = new TargetInvocationHandler(target);
        // 代理對象
        Subject proxy = (Subject) Proxy.newProxyInstance(
                        target.getClass().getClassLoader(),
                        target.getClass().getInterfaces(),
                        invocationHandler);

        // 使用代理對象調用被代理對象的方法
        proxy.sayHello("大家好,我是可愛的小寶貝!");
        proxy.sayHi("小胡", "我是萬人迷");
    }
}

class TargetInvocationHandler implements InvocationHandler {

    private Object target;

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

    private int i = 0;
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("invoke第:" + ++i + "次執行。");
        System.out.println("執行的方法名稱:" + method.getName());

        // 可根據方法名對不同的方法進行增強
        String methodName = method.getName();
        if (methodName.equals("sayHi")) {
            System.out.println("代理之前執行的方法" + i);
            // 執行代理類的方法
            method.invoke(target, args);
            System.out.println("代理之後執行的方法" + i);
        } else {
            // 不增強被代理對象方法
            method.invoke(target, args);
        }
        return null;
    }
}

四、CGLib代理

  • 以上兩種代理模式使用前提都是需要代理對象和目標對象同時實現同一個接口,實際開發中有可能目標對象沒有實現任何接口。而CGLib開發包就是爲了應對這種情況。它採用繼承目標對象的方式實現了代理功能。

  • 需要依賴如下開發包:

    	<!--springframework中已經包含此包,重複導入會導致java.lang.VerifyError錯誤-->
        <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>${cglib.version}</version>
        </dependency>
    
package com.fatsea.news.pattern.structural;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @Author: Chunhai.Hu
 * @Date: 2021/4/28 16:02
 * @Desc: 代理模式(CGLib動態代理方式)測試
 * 被代理對象不必實現某個接口即可進行代理
 * CGLIB原理:繼承目標對象,重寫目標對象的方法
 */
public class CglibProxyTest {
    public static void main(String[] args) {
        RealPerson target = new RealPerson();
        RealPerson proxy  = new CglibRealPerson(target).createProxy();
        proxy.sayHello("我是CGLib代理的對象");
        proxy.sayHi("小王", "我是最可愛的人");
    }
}

// 代理對象:實現MethodInterceptor接口即可
class CglibRealPerson implements MethodInterceptor {

    private RealPerson target;

    public CglibRealPerson(RealPerson target) {
        this.target = target;
    }

    /**
     * @對外暴露代理對象
     * @return
     */
    public RealPerson createProxy () {
        Enhancer enhancer = new Enhancer();
        // 指定父類
        enhancer.setSuperclass(RealPerson.class);
        // 指定回調方法
        enhancer.setCallback(this);
        // 返回代理對象
        return (RealPerson) enhancer.create();
    }

    private int i = 0;
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("invoke第:" + ++i + "次執行。");
        System.out.println("執行的方法名稱:" + method.getName());

        System.out.println("代理之前執行的方法" + i);
        method.invoke(target, objects);
        System.out.println("代理之後執行的方法" + i);
        return null;
    }
}

// 目標對象:沒有實現任何接口
class RealPerson {
    public void sayHello (String word) {
        System.out.println(word);
    }

    public void sayHi (String name, String word) {
        System.out.println("我是:" + name + "***說:***" + word);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章