JAVA 代理模式
簡而言之,代理是一種通過創建代理對象的方式,從而實現對被代理對象實現功能增強的一種方式,JAVA 中有靜態和動態兩種代理,動態代理又可以分爲基於接口的動態代理(JDK 實現)和基於子類的動態代理(cglib 實現),這裏我們講解基於子類的動態代理
基於子類的動態代理(cglib 實現的動態代理)
使用代理的好處就是在不修改原代碼的基礎上可以實現對原方法的增強,使用JDK
官方的動態代理主要是依靠Proxy
類,這種方法實現的動態代理要求被代理類至少實現一個接口,沒有實現接口的類是不能被代理的
那麼沒有實現接口或者不需要實現接口的類,我們怎麼對它進行代理呢?
通過引入第三方cglib
庫,我們可以實現基於子類的動態代理,使用cglib
實現的動態代理也有一個約束條件,就是被代理類不能是最終類
使用cglib
實現的動態代理核心是Enhancer
類,其實實現的過程和JDK
實現動態代理的過程極其類似
導入 jar 包
我是用的是maven
工程,所以第一步是要導入cglib
的 jar 包,當然手動導入也沒有問題,pom.xml
文件配置如下:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.1_3</version>
</dependency>
編寫被代理類
我這裏被代理類主要就實現一個賣東西的功能,之後我們會通過代理類對被代理類中的方法進行增強操作:
package com.lmh.cglib;
import com.lmh.proxy.IPorducer;
/**
* 生產者
*/
public class Producer {
public void saleProduct(float money) {
System.out.println("銷售產品,拿到錢 " + money);
}
}
編寫代理類(這裏也是一個測試類)
這一步是整個過程的關鍵,代理類的實現要通過Enhancer
類,我們需要通過Enhancer
類中的create
方法創建一個代理對象,具體實現方法如下,作用是給售價打八折,後面我會詳細的解釋各部分的功能
package com.lmh.cglib;
import com.lmh.proxy.IPorducer;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 模擬一個消費者
*/
public class Client {
public static void main(String[] args) {
Producer producer = new Producer();
Producer enhancerProducer = (Producer) Enhancer.create(producer.getClass(), new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
// 提供增強代碼
Object returnValue = null;
Float money = (Float) objects[0];
if ("saleProduct".equals(method.getName())) {
returnValue = method.invoke(producer, money * 0.8f);
}
return returnValue;
}
});
enhancerProducer.saleProduct(1000f);
}
}
這裏我們可以看到,enhancerProducer
就是我們創建的代理對象,這個對象可以執行被代理類中所有的方法,並且我們可以在代理對象中對被代理類的方法進行增強,這裏使用了強轉,因爲create
方法的返回值是Object
類型的對象
create
方法有兩個參數,分別是Class type
和Callback callback
,其中Class type
是值被代理類的字節碼文件,這是固定的,因爲有了被代理類的字節碼後,就相當於可以獲取被代理類的全部信息;Callback callback
是用於提供增強代碼的,一般都是寫一個接口的實現,通常情況下都是匿名內部類,這裏我們一般不適用Callback
接口,而是使用它的子接口實現類MethodInterceptor
MethodInterceptor
接口需要重寫intercept
方法,intercept
方法中的內容即爲對被代理類的增強,該方法有四個參數:Object o
、Method method
、Object[] objects
和MethodProxy methodProxy
Object o
參數,是一個代理對象的引用,Method method
是當前執行,即被攔截的被代理類方法,Objects[] objects
是當前執行方法所用的參數,索引順序即爲方法定義時參數的順序,MethodProxy methodProxy
指的是當前執行的方法的代理對象
通過向上述代碼一樣編寫,我們就可以實現對被代理類功能的增強!