java代理模式學習,靜態代理,JDK動態代理,CGLIB動態代理
java代理模式學習,靜態代理,JDK動態代理,CGLIB動態代理
一、理解代理
1、代理,Proxy 。意思是:本來該你做的事兒,別人代替你去做。 比如說:即將十一到來,你要搶回家/旅遊的車票,可是你不能時時刻刻在電腦前一遍又一遍的刷著12306。 這時交給了 飛豬 等(此處省去若干個搶票軟體!)軟體幫助你搶。 飛豬就是你 搶票 這項工作的代理 。
2、代理作用: 日誌記錄,效能分析,解耦合。。。 自己百度去。
二、靜態代理 --- 程式碼來搶票
1、 定義一個搶票介面 Tickets
/**
* description: 搶票介面 --- 需要搶票需實現該介面
* @version v1.0
* @author w
* @date 2018年9月3日下午9:54:28
*/
public interface Tickets {
void buyTickets();
}
2、定義一個User類 實現搶票介面,執行搶票操作
/** * description: 定義一個User類 實現搶票介面,執行搶票操作 * @version v1.0 * @author w * @date 2018年9月3日下午9:52:38 */ public class User implements Tickets{ private String name; public User(String name) { this.name = name; } @Override public void buyTickets() { System.out.println(name + " 開始搶票啦~ "); } }
3、定義一個FliggyProxy類,實現搶票介面 --- 飛豬來幫你搶票啦
/** * description: 飛豬 實現搶票介面 --- 飛豬來幫你搶票啦 * @version v1.0 * @author w * @date 2018年9月3日下午9:58:44 */ public class FliggyProxy implements Tickets { private User user ; public FliggyProxy(User user) { this.user = user; } @Override public void buyTickets() { System.out.println("充錢,享受1000M專線搶票 "); user.buyTickets(); System.out.println("搶票成功. 廣告:沒有什麼是充錢解決不的問題."); } }
4、定義一個 StaticProxyTest類,執行相關的測試操作
/**
* description: 靜態代理 test
* @version v1.0
* @author w
* @date 2018年9月3日下午10:01:26
*/
public class StaticProxyTest {
@Test
public void testOne(){
// 建立一個使用者,小明 --- 一遍又一遍的刷著12306
User user = new User("小明");
user.buyTickets();
}
@Test
public void testTwo(){
// 建立一個需要搶票的使用者 --- 萬能小明
User user = new User("萬能小明");
// 小明開啟飛豬
FliggyProxy fliggy = new FliggyProxy(user);
// fliggy 開始搶票啦
fliggy.buyTickets();
}
}
5、執行結果:
testOne:小明 開始搶票啦~
testTwo:
充錢,享受1000M專線搶票
萬能小明 開始搶票啦~
搶票成功. 廣告:沒有什麼是充錢解決不的問題.
6、根據程式碼執行結果可以小明搶票的操作,交給飛豬後,很快就搶到了。 但是 飛豬的功能太單一,只能幫忙搶票。比如下次要搶月餅呢,再下次要搶手機呢? 要實現這些功能,我們就要寫n多個的 xxProxy。 作為程式設計師,總想著一勞永逸,能否只寫一個呢? 答案是有的,繼續往下。
三、JDK動態代理
1、定義一個 FliggyDynamic 類,實現 java.lang.reflect.InvocationHandler 介面
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* description: JDK動態代理。 飛豬動態幫助無數人開啟搶票模式
* @version v1.0
* @author w
* @date 2018年9月3日下午10:06:21
*/
public class FliggyDynamic implements InvocationHandler {
/**
* 需要搶票的使用者 --- 目標代理物件
*/
private Object target ;
/**
* 構造方法,初始化目標代理物件
*/
public FliggyDynamic(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("充錢,享受1000M專線搶票 ");
Object result = method.invoke(target, args);
System.out.println("搶票成功. 廣告:沒有什麼是充錢解決不的問題.");
return result;
}
}
2、定義一個 DynamicTest類,執行相關的測試操作
/**
* description: JDK 動態代理Test
* @version v1.0
* @author w
* @date 2018年9月3日下午10:09:02
*/
public class DynamicTest {
@Test
public void test(){
User user = new User("萬年小明");
FliggyDynamic dynamic = new FliggyDynamic(user);
Tickets proxy = (Tickets)Proxy.newProxyInstance(user.getClass().getClassLoader(),
user.getClass().getInterfaces(), dynamic);
proxy.buyTickets();
}
}
3、執行結果:
充錢,享受1000M專線搶票
萬年小明 開始搶票啦~
搶票成功. 廣告:沒有什麼是充錢解決不的問題.
4、定義 FliggyDynamicRefactor<T>類,實現 InvocationHandler 介面,增加泛型。 (可選)
重構獲取代理物件方法: Proxy.newProxyInstance .... 避免每次都進行強制型別轉換。
/**
* description: JDK動態代理 。 重構 Proxy.newProxyInstance , 避免每次都進行強制型別轉換。
* @version v1.0
* @author w
* @date 2018年9月3日下午10:52:07
*/
public class FliggyDynamicRefactor<T> implements InvocationHandler{
/**
* 目標代理物件 target
*/
private T target ;
public FliggyDynamicRefactor(T target) {
this.target = target;
}
/**
* description: 獲取代理物件
* @return
* T
* @version v1.0
* @author w
* @date 2018年9月3日 下午10:55:59
*/
@SuppressWarnings("unchecked")
public T getProxy(){
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("充錢,享受1000M專線搶票 ");
Object result = method.invoke(target, args);
System.out.println("搶票成功. 廣告:沒有什麼是充錢解決不的問題.");
return result;
}
}
5、定義 DynamicRefactorTest 類,對重構後的程式碼進行測試 (可選)
/**
* description: JDK 動態代理 重構後的 FliggyDynamicRefactor Test
* @version v1.0
* @author w
* @date 2018年9月3日下午10:09:02
*/
public class DynamicRefactorTest {
@Test
public void test(){
FliggyDynamicRefactor<Tickets> refactor = new FliggyDynamicRefactor<Tickets>(new User("李雷"));
refactor.getProxy().buyTickets();
}
}
6、執行結果:
充錢,享受1000M專線搶票
李雷 開始搶票啦~
搶票成功. 廣告:沒有什麼是充錢解決不的問題.
7、使用JDK提供的動態代理,可以解決靜態代理中要寫 n多個 xxProxy類的問題。但是可以發現,JDK動態代理只能針對介面的代理。 若一個類,沒有實現任何介面,那麼JDK的動態代理也就無用武之地了。 有解決辦法嗎?有,繼續看 CGLIB的動態代理 ---- 針對類的代理。
四、CGLIB動態代理
1、 依賴jar包: cglib-3.2.6.jar
2、定義一個 Car 類,不實現任何 介面的普普通通類
/**
* description: 定義一個普通的 Car類
* @version v1.0
* @author w
* @date 2018年9月3日下午11:27:09
*/
public class Car {
public void runing(){
System.out.println("老司機開車啦~ ");
}
}
3、定義一個 CglibProxy類,實現 net.sf.cglib.proxy.MethodInterceptor 介面
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* description: 使用 CGLIB 實現動態代理
* @version v1.0
* @author w
* @date 2018年9月3日下午11:12:55
*/
public class CglibProxy implements MethodInterceptor{
@SuppressWarnings("unchecked")
public <T> T getProxy(Class<T> clzz){
return (T) Enhancer.create(clzz, this);
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("前方注意~老司機來了,請速讓道。。 ");
Object result = proxy.invokeSuper(obj, args);
System.out.println("老司機已通過前方 over ..");
return result;
}
}
4、定義 CglibProxyTest類,針對CglibProxy的測試
/**
* description: 針對 CglibProxy 的測試
* @version v1.0
* @author w
* @date 2018年9月3日下午11:46:34
*/
public class CglibProxyTest {
@Test
public void test(){
CglibProxy proxy = new CglibProxy();
Car car = proxy.getProxy(Car.class);
car.runing();
}
}
5、執行結果:
前方注意~老司機來了,請速讓道。。
老司機開車啦~
老司機已通過前方 over ..
6、可以看到,使用 CGLIB解決了JDK的動態代理只能針對介面代理的問題。 普通的java類都可以進行代理。
五、總結
1、代理模式,實現程式碼功能增強,且不影響原始碼,解耦合。
2、靜態代理,針對每一個代理物件都需要都需要一個代理類。
3、JDK動態代理,只能針對介面代理,若目標代理類未實現介面,則無法代理。
4、CGLIB動態代理,可以對普通類進行代理,但目標代理類需提供無參構造方法。
參考資料: http://www.importnew.com/26116.html