設計模式---代理模式

代理模式:

為一個對象提供一個替身,以控制對這個對象的訪問。即通過代理對象訪問目標對象。這樣做的好處是可以在目標對象實現的基礎上,增強額外的功能操作,擴展目標對象的功能。比方說數學老師休產假了,這個時候就需要另外一個老師來代課了,而代課老師不僅僅會上數學課,還會在數學課上給同學們講一些課外的東西。

被代理的對象可以是遠程對象、創建開銷大的對象或需要安全控制的對象

 

代理模式主要有三種類型,靜態代理,動態代理,也叫JDK代理或者接口代理,還有cglib代理,其實這個也屬于動態代理范疇吧,只是JDK動態必須是接口,cglib可以不是接口

 

靜態代理

靜態代理在使用時,需要定義接口或者父類,被代理對象(目標對象)與代理對象一起實現相同的接口或者是繼承相同父類

Teacher 接口,代理類TeacherLiProxy和目標對象TeacherLi均實現該接口,同時TeacherLiProxy聚合目標對象。重寫接口方法。在其中做擴展。

類圖如下:

 

 

 

 

優點:在不修改目標對象的功能前提下, 能通過代理對象對目標功能擴展

缺點:因為代理對象需要與目標對象實現一樣的接口,所以會有很多代理類;一旦接口增加方法,目標對象與代理對象都要維護

Teacher

package com.nijunyang.designpatterns.proxy.staticproxy;

/**
 * @author: create by nijunyang
 * @date:2019/10/5
 */
public interface Teacher {
    void teach();
}

 TeacherLi

package com.nijunyang.designpatterns.proxy.staticproxy;

/**
 * @author: create by nijunyang
 * @date:2019/10/5
 */
public class TeacherLi implements Teacher {
    @Override
    public void teach() {
        System.out.println("上數學課");
    }
}

 TeacherLiProxy

package com.nijunyang.designpatterns.proxy.staticproxy;

/**
 * @author: create by nijunyang
 * @date:2019/10/5
 */
public class TeacherLiProxy implements Teacher{
    //聚合代理的目標對象
    private Teacher target;

    public TeacherLiProxy(Teacher target) {
        this.target = target;
    }

    @Override
    public void teach() {
        System.out.println("代課開始..");
        target.teach();
        System.out.println("代課結束..");
    }
}

 Test

 

package com.nijunyang.designpatterns.proxy.staticproxy;

/**
 * @author: create by nijunyang
 * @date:2019/10/5
 */
public class Test {
    public static void main(String[] args)
    {
        TeacherLi teacherLi = new TeacherLi();
        TeacherLiProxy teacherLiProxy = new TeacherLiProxy(teacherLi);
        teacherLiProxy.teach();
    }
}

 

 

 

JDK代理:

代理對象,不需要實現接口,但是目標對象要實現接口,否則不能用動態代理

代理對象的生成,是利用JDK的API,動態的在內存中構建代理對象。需要利用java.lang.reflect.Proxy#newProxyInstance

TeacherLi目標對象實現Teacher接口,

ProxyFactory#getProxyInstance生成代理對象,該方法中使用java.lang.reflect.Proxy#newProxyInstance生成代理對象。

 

 

ProxyFactory
package com.nijunyang.designpatterns.proxy.dynamicproxy;

import java.lang.reflect.Proxy;

/**
 * @author: create by nijunyang
 * @date:2019/10/5
 */
public class ProxyFactory<T> {

    //目標對象
    private T target;

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

    //給目標對象生成一個代理
    public T getProxyInstance() {
        //1.ClassLoader loader 目標對象使用的類加載器
        //2.Class<?>[] interfaces 目標對象實現的接口
        //3.InvocationHandler h   事件處理,執行目標對象方法時會觸發事件處理器方法, 會把當前執行的目標對象方法作為參數傳入
        return (T) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                (proxy, method, args) -> {
                    System.out.println("JDK代理");
                    Object result = method.invoke(target, args);
                    System.out.println("JDK代理結束");
                    return result;

                });
    }
}

 Test

 

package com.nijunyang.designpatterns.proxy.dynamicproxy;

/**
 * @author: create by nijunyang
 * @date:2019/10/5
 */
public class Test {
    public static void main(String[] args)
    {
        TeacherLi teacherLi = new TeacherLi();
        Teacher proxyTeacher = new ProxyFactory<>(teacherLi).getProxyInstance();
        System.out.println(proxyTeacher.getClass());
        proxyTeacher.teach();
    }
}

 

 

Cglib代理:

靜態代理和JDK動態代理都需要目標對象實現一個接口,而cglib代理的目標對象不需要實現接口也行。它是從內存中構建一個子類對象來實現對目標對象的擴展。

Cglib是一個強大的高性能的代碼生成包,它可以在運行期擴展java類與實現java接口。它廣泛的被許多AOP的框架使用,例如Spring AOP,實現方法攔截。

Cglib包的底層是通過使用字節碼處理框架ASM來轉換字節碼并生成新的類。

使用cglib需要導包(cglib,asm,asm-tree,asm-commons)或者用spring框架org.springframework.cglib.proxy包里面的。

需要注意的是:

  1. 在內存中動態構建子類,注意代理的類不能為final,否則報錯 java.lang.IllegalArgumentException
  2. 目標對象的方法如果為final/static,那么就不會被攔截,即不會執行目標對象額外的業務方法.

 

TeacherLi 目標對象,

ProxyFactory實現MethodInterceptor接口,同時聚合目標對象

getProxyInstance生成代理對象,該方法中使用Enhancer工具生成代理對象。

重寫攔截方法intercept

 

 

TeacherLi

package com.nijunyang.designpatterns.proxy.cglibproxy;

/**
 * @author: create by nijunyang
 * @date:2019/10/5
 */
public class TeacherLi {
    public void teach() {
        System.out.println("上數學課...cglib");
    }
}

 ProxyFactory

 

package com.nijunyang.designpatterns.proxy.cglibproxy;

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

import java.lang.reflect.Method;

/**
 * @author: create by nijunyang
 * @date:2019/10/5
 */
public class ProxyFactory implements MethodInterceptor {

    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }
    public Object getProxyInstance() {
        //1. 創建增強器
        Enhancer enhancer = new Enhancer();
        //2. 設置父類
        enhancer.setSuperclass(target.getClass());
        //3. 設置回調函數
        enhancer.setCallback(this);
        //4. 創建代理對象
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib代理");
        Object result = method.invoke(target, args);
        System.out.println("cglib代理結束");
        return result;
    }
}

 Test

 

package com.nijunyang.designpatterns.proxy.cglibproxy;

/**
 * @author: create by nijunyang
 * @date:2019/10/5
 */
public class Test {
    public static void main(String[] args)
    {
        TeacherLi teacherLi = new TeacherLi();
        ProxyFactory proxyFactory = new ProxyFactory(teacherLi);
        TeacherLi proxy = (TeacherLi) proxyFactory.getProxyInstance();
        proxy.teach();
    }
}

 

posted @ 2019-10-05 19:04 白露非霜 閱讀(...) 評論(...) 編輯 收藏
手机投注彩票合法吗