代理在我們生活中并不陌生,假如我現在餓了,我可以選擇直接去飯店吃,也可以通過外賣平臺下單,比如百度外賣、美團外賣、餓了么這些平臺本身不生產產品,他們只是商家的搬運工,可以理解成外賣平臺就是各種商家的代理。
外賣平臺幫我買份飯并送貨上門,不僅節約了我去飯店排隊的麻煩,可以節約自已很多時間,排隊這些細節的問題我不需要關心,目的就是吃上我想吃的飯就ok。我不想自已親自做的事或著做不到的事(比如中午我需要開個會,沒時間去出去),就可以找個代理幫我去做。
現在各大平臺都在搞活動,只要下單就可以打折,“打折”算是代理的一個活動,除了給了我想吃的飯還幫我省了部分錢(有的平臺送優惠劵)。代理可以幫我完成要做的事情,還可以附加一些代理想做的事情
那我們在開發中什么時候用代理模式呢?
1、自已不想做或著做不到的事
2、需要在現有方法基礎上擴展些功能,比如在謀方法執行前后非侵入式打印log
靜態代理
public class ProxyDemo {
public static void main(String args[]){
RealSubject subject = new RealSubject();
ProxySubject p = new ProxySubject(subject);
p.request();
}
}
interface Subject{
void request();
}
class RealSubject implements Subject{
public void request(){
System.out.println("request");
}
}
class ProxySubject implements Subject{
private Subject subject;
public ProxySubject(Subject subject){
this.subject = subject;
}
public void request(){
System.out.println("調用前");
subject.request();
System.out.println("調用后");
}
}
其實代理還有一個作用就是隱藏真正實現細節,做為代理類不需要關心執行的方法是怎么實現的。
按照代理的創建時期,代理類可以分為兩種。
靜態代理:由程序員創建或特定工具自動生成源代碼,再對其編譯。在程序運行前,代理類的.class文件就已經存在了。
動態代理:在程序運行時,運用反射機制動態創建而成。
上邊的實現就是一種靜態代理的實現方式,那啥是動態代理呢,說白了Proxy類是通過反射生成的,AOP (面向切面編程)主要是利用動態代理模式的技術來實現的。
動態代理有2種實現方式:
1、使用JDK的Proxy實現的動態代理
2、使用CGlib實現的動態代理
JDK動態代理中包含一個類和一個接口:
InvocationHandler接口:
public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
}
參數說明:
Object proxy:指被代理的對象。
Method method:要調用的方法
Object[] args:方法調用時所需要的參數
可以將InvocationHandler接口的子類想象成一個代理的最終操作類,替換掉 ProxySubject。
Proxy類:
Proxy類是專門完成代理的操作類,可以通過此類為一個或多個接口動態地生成 實現類,此類提供了如下的操作方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
InvocationHandler h) throws IllegalArgumentException
參數說明:
ClassLoader loader:類加載器
Class<?>[] interfaces:得到全部的接口
InvocationHandler h:得到InvocationHandler接口的子類實例
實現方式:
public class DynamicProxyDemo01 {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject(); //1.創建委托對象
ProxyHandler handler = new ProxyHandler(realSubject); //2.創建調用處理器對象
Subject proxySubject = (Subject)Proxy.newProxyInstance(RealSubject.class.getClassLoader(),
RealSubject.class.getInterfaces(), handler); //3.動態生成代理對象
proxySubject.request(); //4.通過代理對象調用方法
}
}
/**
* 接口
*/
interface Subject{
void request();
}
/**
* 委托類
*/
class RealSubject implements Subject{
public void request(){
System.out.println("====RealSubject Request====");
}
}
/**
* 代理類的調用處理器
*/
class ProxyHandler implements InvocationHandler{
private Subject subject;
public ProxyHandler(Subject subject){
this.subject = subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("調用前");
Object result = method.invoke(subject, args);
System.out.println("調用后");
return result;
}
}
使用CGlib實現的動態代理
public class DynamicProxyDemo02 {
public static void main(String[] args) {
RealSubjectCglib cglib=new RealSubjectCglib();
RealSubject realSubject=(RealSubject)cglib.getInstance(new RealSubject());
realSubject.request();
}
/**
*沒有實現接口的委拖類
*/
class RealSubject {
public void request(){
System.out.println("====RealSubject Request====");
}
}
public class RealSubjectCglib implements MethodInterceptor {
private Object target;
/**
* 創建代理對象
*
* @param target
* @return
*/
public Object getInstance(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
// 回調方法
enhancer.setCallback(this);
// 創建代理對象
return enhancer.create();
}
@Override
// 回調方法
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("調用前");
proxy.invokeSuper(obj, args);
System.out.println("調用后");
return null;
}
}
}
JDK的動態代理機制只能代理實現了接口的類,而不能實現接口的類就不能實現JDK的動態代理,cglib是針對類來實現代理的,他的原理是對指定的目標類生成一個子類,并覆蓋其中方法實現增強,但因為采用的是繼承,所以不能對final修飾的類進行代理。