1. 程式人生 > >Java基礎加強——動態代理

Java基礎加強——動態代理

pack lan 自動 構造器 interface 其中 tex ide count

代理模式:

  為其他對象提供一種代理以控制對這個對象的訪問。

  代理模式主要分為兩類:

    靜態代理:由程序員創建或特定工具自動生成源代碼,再對其編譯。在程序運行前,代理類的.class文件就已經存在了。
    動態代理:在程序運行時,運用反射機制動態創建而成

 1.靜態代理相對好理解一些,來看下面的代碼:

    接口 Count.java

/**
 * 賬戶接口
 * @author jiangbei01
 *
 */
public interface Count {
    void add();
    void update();
}

    實現類 CountImpl

package
cn.test; public class CountImpl implements Count { @Override public void add() { System.out.println("真實對象.add"); } @Override public void update() { System.out.println("真實對象.update"); } }

    代理對象CountProxy.java

package cn.test;

public class CountProxy implements
Count { //持有真實對象引用 private CountImpl countImpl; //覆蓋默認構造器 public CountProxy(CountImpl countImpl) { super(); this.countImpl = countImpl; } @Override public void add() { System.out.println("代理對象執行add前"); countImpl.add(); System.out.println(
"代理對象執行add後"); } @Override public void update() { System.out.println("代理對象執行update前"); countImpl.update(); System.out.println("代理對象執行update後"); } }

    看看測試代碼:

public class Test01 {

    public static void main(String[] args) {
        CountImpl countImpl = new CountImpl();
        CountProxy countProxy = new CountProxy(countImpl);
        countProxy.add();
        System.out.println("===========================");
        countProxy.update();
    }
}

    運行結果也容易得出:

代理對象執行add前
真實對象.add
代理對象執行add後
===========================
代理對象執行update前
真實對象.update
代理對象執行update後

  容易看出靜態代理缺點:每個代理只能為一個接口服務,並且重復代碼量大!

2.動態代理:java.lang.reflect 包中的Proxy類和InvocationHandler 接口提供了生成動態代理類的能力。

  Proxy類提供的方法:

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

其中最後一個參數 InvocationHandler h 得到InvocationHandler接口的子類實例

  ClassLoader loader用來指明生成代理對象使用哪個類裝載器,(Proxy.class.getClassLoader())

  Class<?>[] interfaces用來指明生成哪個對象的代理對象,通過接口指定,

  InvocationHandler h用來指明產生的這個代理對象要做什麽事情。

  下面來看一個例子:

  先定義一個接口:Person.java

public interface Person {

    String sing(String musicName);
    String speak(String text);
}

  給出一個實現類:薛之謙 XueZhiQian.java

public class XueZhiQian implements Person {

    @Override
    public String sing(String musicName) {
        System.out.println("薛之謙唱了 "+musicName);
        return "歌曲唱完,謝謝各位!";
    }

    @Override
    public String speak(String text) {
        System.out.println("薛之謙說了 "+text);
        return "話已講完,謝謝各位!";
    }

}

    生成代理對象的代理類:XueZhiQianProxy.java

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

public class XueZhiQianProxy {

    //要代理的對象
    private Person xzq = new XueZhiQian();
    
    public Person getProxy(){
        return (Person)Proxy.newProxyInstance(XueZhiQianProxy.class.getClassLoader(), 
                xzq.getClass().getInterfaces(), 
                new InvocationHandler() {
                    
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        if(method.getName().equals("sing")){
                            System.out.println("找薛之謙唱歌需要先交2W!");
                            return method.invoke(xzq, args);
                        }
                        if(method.getName().equals("speak")){
                            System.out.println("找薛之謙唱歌需要先交10W!");
                            return method.invoke(xzq, args);
                        }
                        return null;
                    }
                });
    }
}

    測試代碼:

public class Test01 {

    public static void main(String[] args) {
        XueZhiQianProxy proxy = new XueZhiQianProxy();
        Person p = proxy.getProxy();
        String s1 = p.sing("演員");
        System.out.println(s1);
        String s2 = p.speak("段子");
        System.out.println(s2);
    }
}

    測試結果:

找薛之謙唱歌需要先交2W!
薛之謙唱了 演員
歌曲唱完,謝謝各位!
找薛之謙唱歌需要先交10W!
薛之謙說了 段子
話已講完,謝謝各位!

  

Java基礎加強——動態代理