Java基礎加強——動態代理
阿新 • • 發佈:2017-05-09
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基礎加強——動態代理