代理模式


一 代理模式簡介

代理(Proxy)是一種設計模式 提供了對目標對象另外的訪問方式

代理對象代理目標對象 達到增強目標對象功能的目的

 

二 靜態代理

需要定義接口或者父類 代理對象與目標對象一起實現相同接口或者繼承相同父類

優點: 在不修改目標對象的功能前提下 對目標功能擴展

缺點: 因為代理對象需要與目標對象一起實現相同接口或者繼承相同父類 所以會有很多代理類 導致類太多 同時 如果接口增加方法 代理對象與目標對象都要維護

1. 接口

/**
 * 接口
 * Created by Hy on 2020/7/10.
 */
public interface IUserService {

    void insertUser();

    String deleteUser(int id);
}

2. 目標對象

/**
 * 目標對象
 * Created by Hy on 2020/7/10.
 */
public class UserService implements IUserService {

    @Override
    public void insertUser() {
        System.out.println("insert ok");
    }

    @Override
    public String deleteUser(int id) {
        System.out.println("delete... ... ...");
        return "id = " + id + " delete ok";
    }
}

3. 代理對象

/**
 * 代理對象
 * Created by Hy on 2020/7/13.
 */
public class UserServiceProxy implements IUserService {

    private IUserService target; //目標對象

    public UserServiceProxy(IUserService target) {
        this.target = target;
    }

    @Override
    public void insertUser() {
        System.out.println("增強方法體 1/2");
        target.insertUser();
        System.out.println("增強方法體 2/2");
    }

    @Override
    public String deleteUser(int id) {
        id++; //增強參數
        String s = target.deleteUser(id);
        s = s + "!!!"; //增強返回值
        return s;
    }
}

4. 測試

@Test
public void test01() {
    // 創建目標對象
    UserService target = new UserService();
    // 創建代理對象
    UserServiceProxy proxy = new UserServiceProxy(target);
    // 使用代理對象調用方法
    proxy.insertUser();
    String s = proxy.deleteUser(1);
    System.out.println(s);
}

 

三 動態代理(接口代理)

需要定義接口讓目標對象實現 使用java.lang.reflect.Proxy動態的在內存中構建代理對象

優點: 在不修改目標對象的功能前提下 對目標功能擴展 代理對象不需要實現接口

缺點: 目標對象一定要實現接口 否則不能用動態代理

1. 接口

/**
 * 接口
 * Created by Hy on 2020/7/10.
 */
public interface IUserService {

    void insertUser();

    String deleteUser(int id);
}

2. 目標對象

/**
 * 目標對象
 * Created by Hy on 2020/7/10.
 */
public class UserService implements IUserService {

    @Override
    public void insertUser() {
        System.out.println("insert ok");
    }

    @Override
    public String deleteUser(int id) {
        System.out.println("delete... ... ...");
        return "id = " + id + " delete ok";
    }
}

3. 代理工廠

/**
 * 代理工廠
 * Created by Hy on 2020/7/13.
 */
public class ProxyFactory {

    private Object target; //目標對象

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

    public Object createProxyInstance() {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
            /**
             * 代理對象調用的所有方法都會觸發該方法執行
             * @param proxy 代理對象
             * @param method 被代理的方法
             * @param args 被代理的方法傳參
             * @return 被代理的方法返回值
             * @throws Throwable 異常
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if ("deleteUser".equals(method.getName())) {
                    // 增強指定方法
                    int id = (int) args[0];
                    id++; //增強參數
                    System.out.println("增強方法體 1/2");
                    String invoke = (String) method.invoke(target, id);
                    invoke = invoke + "!!!"; //增強返回值
                    System.out.println("增強方法體 2/2");
                    return invoke;

                } else {
                    // 其它方法默認實現
                    Object invoke = method.invoke(target, args);
                    return invoke;
                }
            }
        });
    }
}

4. 測試

@Test
public void test01() {
    // 創建目標對象
    UserService target = new UserService();
    System.out.println(target.getClass());
    // 創建代理對象
    IUserService proxy = (IUserService) new ProxyFactory(target).createProxyInstance();
    System.out.println(proxy.getClass());
    // 使用代理對象調用方法
    proxy.insertUser();
    String s = proxy.deleteUser(1);
    System.out.println(s);
}

 

 四 CGLIB代理(子類代理)

通過在內存中構建一個子類對象從而實現對目標對象功能的擴展 CGLIB是一個強大的高性能的代碼生成包 底層使用一個小而快的字節碼處理框架ASM來轉換字節碼並生成新的類

優點: 在不修改目標對象的功能前提下 對目標功能擴展 代理對象與目標對象都不需要實現接口

缺點: 需要引入CGLIB的JAR文件

1. 目標對象

/**
 * 目標對象
 * Created by Hy on 2020/7/10.
 */
public class UserService {

    public void insertUser() {
        System.out.println("insert ok");
    }

    public String deleteUser(int id) {
        System.out.println("delete... ... ...");
        return "id = " + id + " delete ok";
    }
}

2. 代理工廠

/**
 * 代理工廠
 * Created by Hy on 2020/7/13.
 */
public class ProxyFactory {

    private Object target; //目標對象

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

    public Object createProxyInstance() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(new MethodInterceptor() {
            /**
             * 代理對象調用的所有方法都會觸發該方法執行
             * @param proxy 代理對象
             * @param method 被代理的方法
             * @param args 被代理的方法傳參
             * @param methodProxy 代理的方法
             * @return 被代理的方法返回值
             * @throws Throwable 異常
             */
            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                if ("deleteUser".equals(method.getName())) {
                    // 增強指定方法
                    int id = (int) args[0];
                    id++; //增強參數
                    System.out.println("增強方法體 1/2");
                    String invoke = (String) method.invoke(target, id);
                    invoke = invoke + "!!!"; //增強返回值
                    System.out.println("增強方法體 2/2");
                    return invoke;

                } else {
                    // 其它方法默認實現
                    Object invoke = methodProxy.invokeSuper(proxy, args); //等同 method.invoke(target, args);
                    return invoke;
                }
            }
        });
        return enhancer.create();
    }
}

3. 測試

@Test
public void test01() {
    // 創建目標對象
    UserService target = new UserService();
    System.out.println(target.getClass());
    // 創建代理對象
    UserService proxy = (UserService) new ProxyFactory(target).createProxyInstance();
    System.out.println(proxy.getClass());
    // 使用代理對象調用方法
    proxy.insertUser();
    String s = proxy.deleteUser(1);
    System.out.println(s);
}

 


免責聲明!

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



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