一,代理模式
代理模式:
- 爲對象提供一個替身,以控制對這個對象的訪問。即通過代理對象訪問目標對象,可以在目標對象的基礎上實現擴展,增強額外的功能;
- 被代理對象可以是遠程對象、創建開銷大的對象或需要安全控制的對象等;
- 主要有:靜態代理,jdk動態代理,Cglib動態代理
二,原理類圖
意圖: 爲其他對象提供一種代理以控制對這個對象的訪問。
適用性:
在需要用比較通用和複雜的對象指針代替簡單的指針的時候,使用Proxy模式。下面是一 些可以使用Proxy 模式常見情況:
- 遠程代理(Remote Proxy )爲一個對象在不同的地址空間提供局部代表。 NEXTSTEP[Add94] 使用NXProxy 類實現了這一目的。Coplien[Cop92] 稱這種代理爲“大使” (Ambassador )。
- 虛代理(Virtual Proxy )根據需要創建開銷很大的對象。在動機一節描述的ImageProxy 就是這樣一種代理的例子。
- 保護代理(Protection Proxy )控制對原始對象的訪問。保護代理用於對象應該有不同 的訪問權限的時候。例如,在Choices 操作系統[ CIRM93]中KemelProxies爲操作系統對象提供 了訪問保護。
- 智能指引(Smart Reference )取代了簡單的指針,它在訪問對象時執行一些附加操作。 它的典型用途包括:對指向實際對象的引用計數,這樣當該對象沒有引用時,可以自動釋放它(也稱爲SmartPointers[Ede92 ] )。
當第一次引用一個持久對象時,將它裝入內存。
在訪問一個實際對象前,檢查是否已經鎖定了它,以確保其他對象不能改變它。
三,實例
靜態代理
靜態代理: 定義接口或者父類,被代理對象和代理對象一起實現或繼承;
優點: 在不修改被代理類的前提下實現功能擴展增強;
缺點: 同時需要繼承或實現同一個接口,一旦接口方法增加所有代理和被代理類都需要調整;
接口
package com.neei.proxy.statis;
/**
* @param
* @Author: AaNeei
* @Date: 2019/10/11 21:35
* @Description: 遊學網
* @throws:
*/
public interface ITeacher {
void teach();
}
被代理類
package com.neei.proxy.statis;
/**
* @param
* @Author: AaNeei
* @Date: 2019/10/11 21:34
* @Description: 遊學網
* @throws:
*/
public class Teacher implements ITeacher {
@Override
public void teach(){
System.out.println("老師上課中。。。。");
}
}
代理類
package com.neei.proxy.statis;
/**
* @param
* @Author: AaNeei
* @Date: 2019/10/11 21:36
* @Description: 遊學網
* @throws:
*/
public class TeacherProxy implements ITeacher {
private ITeacher iTeacher;
public TeacherProxy(ITeacher iTeacher) {
this.iTeacher = iTeacher;
}
@Override
public void teach() {
System.out.println("靜態代理開始-----功能增強");
iTeacher.teach();
System.out.println("功能增強完畢-----靜態代理結束");
}
}
調用
package com.neei.proxy.statis;
/**
* @param
* @Author: AaNeei
* @Date: 2019/10/11 21:38
* @Description: 遊學網
* @throws:
*/
public class Client {
public static void main(String[] args) {
Teacher teacher = new Teacher();
TeacherProxy proxy=new TeacherProxy(teacher);
proxy.teach();
}
}
JDK動態代理
JDK動態代理:
- 代理對象不需要實現接口,被代理對象需要實現接口,又叫接口代理
- 代理對象的生成是通過JDK的API,動態的在內存中構建的;
接口
package com.neei.proxy.statis;
/**
* @param
* @Author: AaNeei
* @Date: 2019/10/11 21:35
* @Description: 遊學網
* @throws:
*/
public interface ITeacher {
void teach();
}
被代理類
package com.neei.proxy.statis;
/**
* @param
* @Author: AaNeei
* @Date: 2019/10/11 21:34
* @Description: 遊學網
* @throws:
*/
public class Teacher implements ITeacher {
@Override
public void teach(){
System.out.println("老師上課中。。。。");
}
}
代理類
package com.neei.proxy.dynamic;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @param
* @Author: AaNeei
* @Date: 2019/10/11 21:56
* @Description: 遊學網
* @throws:
*/
public class ProxyFactory {
private Object object;
public ProxyFactory(Object object) {
this.object = object;
}
public Object getProxyInstance() {
return Proxy.newProxyInstance(
//代理對象的類加載器
object.getClass().getClassLoader(),
//代理對象實現的接口集合
object.getClass().getInterfaces(),
//方法處理攔截器
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK動態代理開始---");
return method.invoke(object, args);
}
});
}
}
調用
package com.neei.proxy.dynamic;
/**
* @param
* @Author: AaNeei
* @Date: 2019/10/11 21:55
* @Description: 遊學網
* @throws:
*/
public class Client {
public static void main(String[] args) {
ITeacher teacher=new Teacher();
ITeacher instance = (ITeacher) new ProxyFactory(teacher).getProxyInstance();
instance.teach();
}
}
CGLIB動態代理
CGLIB動態代理:
- 靜態代理和jdk動態代理都需要實現接口,如果沒有接口實現的時候就只能使用cglib代理;
- cglib又叫子類代理,在內存中構建一個子類對象(不能是final類),實現對目標對象的功能擴展;
- cglib是個高性能的代碼生成包,可以在運行期擴展java類實現、java接口等,多用於AOP框架,實現方法攔截;
- cglib底層採用了asm框架的字節碼技術轉換字節碼並生成新的類;
被代理類
package com.neei.proxy.statis;
/**
* @param
* @Author: AaNeei
* @Date: 2019/10/11 21:34
* @Description: 遊學網
* @throws:
*/
public class Teacher implements ITeacher {
@Override
public void teach(){
System.out.println("老師上課中。。。。");
}
}
代理類
package com.neei.proxy.dynamic;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @param
* @Author: AaNeei
* @Date: 2019/10/11 21:56
* @Description: 遊學網
* @throws:
*/
public class ProxyFactory implements MethodInterceptor {
private Object object;
public ProxyFactory(Object object) {
this.object = object;
}
public Object getProxyInstance() {
//創建工具類
Enhancer enhancer = new Enhancer();
//設置目標類
enhancer.setSuperclass(object.getClass());
//回調目標類方法
enhancer.setCallback(this);
//返回代理對象
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib動態代理開始----");
Object invoke = method.invoke(object, args);
return invoke;
}
}
調用
package com.neei.proxy.dynamic;
/**
* @param
* @Author: AaNeei
* @Date: 2019/10/11 21:55
* @Description: 遊學網
* @throws:
*/
public class Client {
public static void main(String[] args) {
Teacher teacher=new Teacher();
Teacher instance = (Teacher) new ProxyFactory(teacher).getProxyInstance();
instance.teach();
}
}
四,源碼分析
JDK源碼中使用的代理模式,如Proxy.newProxyInstance;