實現代理的幾種方法

代理模式是設計模式結構型中的其中一種
實現代理功能有靜態代理,動態代理,Cglib的幾種方式
如果沒有概念,接下來一一分別代碼簡單實現,看看主要的不同,寫完基本能有個基本認知

代理即 兩個類之間不直接產生關係,而由中間設置的代理類來實現交互。


先做一個例子

1.單純恰飯

學生吃飯,(沒得辦法只會來這些吃飯簡單例子)
老師吃飯。
分別實現Person接口
Person:

public interface Person {
    void eat();
}

Student:

public class Student  implements Person{
	@Override
	public void eat() {
        System.out.println("Student eating");
    }
}

Teacher:


public class Teacher  implements Person{
	@Override
    public void eat() {
        System.out.println("Teachers eating");
    }
}

2.吃飯前運動一下,吃飯後讀一下書

Student:

public class Student  implements Person{
	@Override
	public void eat() {
		System.out.println("play basketball");
        System.out.println("Student eating");
        System.out.println("read 《五年高考三年模擬》");
    }
}

Teacher:

public class Teacher  implements Person{
	@Override
    public void eat() {
    	System.out.println("play basketball");
        System.out.println("Teachers eating");
        System.out.println("read 《五年高考三年模擬》");
    }
}

當然老視也得看五三
那這樣的話我們沒增加一個功能的話都必須老視學生一起改,很繁瑣,七八個十幾個person實現類、
有沒有簡單的一勞永逸的簡單三五行實現的呢,這個還真的有
那就是 代理了,


先說一個 靜態代理

一、靜態代理

靜態代理必須要實現 統一的接口,重寫方法,所不同的是傳入不同的實現類,就會不同的實現,
最後如果再對 吃前後進行增強減弱都可以在代理類中進行更改,student和teacher都不需要再動了

ProxyPerson:

public class ProxyPerson implements Person{

    private Person person = null;

    public ProxyPerson(Person person1) {
        person = person1;
    }
	@Override
    void eatting() {
        System.out.println("washing clothes before eating");
        person.eat();
        System.out.println("run after eated");
    }
}

測試:

/**
     * 靜態代理
     * 實現學生和老師的池
     * 改變代理類的同時不影響原生類
     */
    @Test
    public void smain() {
        ProxyPerson proxyPerson = new ProxyPerson(new Student());
        ProxyPerson proxyPerson2 = new ProxyPerson(new Teacher());
        proxyPerson.eatting();
        System.out.println("-------->>");
        proxyPerson2.eatting();
    }

二、動態代理

動態代理是jdk 自帶的包,不需要額外導入
動態代理的必要條件是必須要實現相同的接口。
基本的實現就是通過反射得到 代理實現,將參數傳入,invoke執行即可
動態代理需要實現 InvocationHandler 接口,重寫 invoke() 方法

public class JDKProxyHandler implements InvocationHandler {

    private Object obj;

    public JDKProxyHandler(Object resut) {
        this.obj = resut;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {


        System.out.println("wash clothes before eat----");
        Object result = method.invoke(obj, args);
        System.out.println("run after ea8888t");

        return result;
    }


    /**
     * 獲取代理 類對象
     *
     * @param <T>
     * @return
     */
    public <T> T getObj() {
        return (T) Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
    }

}

測試方法

/**
     * JDK 自帶的動態代理  必須實現接口
     * 主要是反射method.invoke()
     */
    @Test
    public void getProxy() {
        JDKProxyHandler studentP = new JDKProxyHandler(new Student());
        JDKProxyHandler teacherP = new JDKProxyHandler(new Teacher());
        Person s = studentP.getObj();
        Person t = teacherP.getObj();
        s.eat();
        System.out.println("------------========》》》");
        t.eat();
    }

三、Cglib 織入

JDK 的動態代理需要 實現相同的接口,有一定的侷限性。
而爲了應對這個問題,出現了新技術Cglib

CGLib(Code Generator Library)是一個強大的、高性能的代碼生成庫。底層使用了ASM(一個短小精悍的字節碼操作框架)來操作字節碼生成新的類

而需要使用需要額外導入三方的jar

         <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.2.10</version>
        </dependency>

實現 MethodInterceptor 接口具體的代碼

public class CglibClass implements MethodInterceptor {


    // 單例模式獲取實例
    private static CglibClass cglibClass = new CglibClass();

    public static CglibClass getInstance() {
        return cglibClass;
    }


    // 獲取被代理的目標類
    public <T> T getProxy(Class<T> clazz) {
        return (T) Enhancer.create(clazz, this);
    }


    /**
     * 代理執行目標類方法
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

        System.out.println("read before eated");

        Object invoke = methodProxy.invokeSuper(o, objects);

        System.out.println("run after eated");

        return invoke;
    }

測試方法

 /**
     * cglib  代理目標類,並且在類中進行自定義增強
     */
    @Test
    public void getProxyIn() {
        Person proxy = CglibClass.getInstance().getProxy(Student.class);
        Person proxy2 = CglibClass.getInstance().getProxy(Teacher.class);
        proxy.eat();
        System.out.println("-=-=-=-=-=--=--=--=->>");
        proxy2.eat();
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章