動態代理講解
什麼是動態代理?
一種用於轉發請求,進行特殊處理的機制,“動態”應該指的是“運行期”。
.爲什麼使用動態代理?
可以對請求進行任何處理(如事務,日誌等)
.哪些地方需要動態代理?
不允許直接訪問某些類;對訪問要做特殊處理等
JVM可以在運行時期動態生成出類的字節碼,這種動態生成的類往往被用作代理類,即動態代理類
JVM生成的動態類必須實現一個或多個接口,所以JVM生成的動態類只能用作具有具有相同接口的目標類的代理
CGLIB庫可以動態生成一個類的子類,該子類可以用作該類的代理,如果,沒有實現接口的類生成動態代理類可以使用CGLIB庫
代理類的各個方法中通常除了調用目標的相應方法和對外返回目標返回的結果外,還可以再代理方法中如下四個位置增加
系統功能代碼:
1、在調用目標方法之前;
2、在調用目標方法之後;
3、在調用目標方法前後;
4、在處理目標方法異常的catch塊中;
創建動態類:
創建一個藉口
<span style="font-size:18px;"><strong>import java.lang.reflect.Method;
public interface Advice {
public void beforeMethod(Method method);
public void afterMethod(Method method);
}
</strong></span>
<span style="font-size:18px;"><strong>import java.lang.reflect.Method;
public interface Advice {
public void beforeMethod(Method method);
public void afterMethod(Method method);
}
</strong></span>
<span style="font-size:18px;"><strong>創建一個實現接口的類
import java.lang.reflect.Method;
public class MyAdvice implements Advice{
long beginTime = 0;
public void afterMethod(Method method) {
System.out.println("學習結束了");
long endTime = System.currentTimeMillis();
System.out.println(method.getName() + " 運行時間"
+ (endTime - beginTime));
}
public void beforeMethod(Method method) {
System.out.println("開始學習了");
beginTime = System.currentTimeMillis();
}
<span style="font-size:18px;"><strong>import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;
public class ProxyText {
public static void main(String[] args) throws Exception,
NoSuchMethodException {
// 獲取字節碼
Class clazzProxy1 = Proxy.getProxyClass(Collection.class
.getClassLoader(), Collection.class);
System.out.println(clazzProxy1.getName());
System.out.println("----------begin constructors list------------");
/*
* $Proxy0() $Proxy0(InvocationHandier,int)
*/
// 獲取所有構造方法
Constructor[] constructors = clazzProxy1.getConstructors();
for (Constructor constructor : constructors) {
String name = constructor.getName();
StringBuilder sBuilder = new StringBuilder(name);
sBuilder.append("(");
Class[] clazzPrams = constructor.getParameterTypes();
for (Class clazzPram : clazzPrams) {
if (clazzPrams != null && clazzPrams.length != 0) {
sBuilder.append(clazzPram.getName()).append(",");
}
}
sBuilder.append(")");
System.out.println(sBuilder.toString());
System.out.println("-----------begin methods llist------------");
// 獲得所有的方法
Method[] methods = clazzProxy1.getMethods();
for (Method method : methods) {// 遍歷數組
String name1 = method.getName();// 獲取方法名
StringBuilder sBuilder1 = new StringBuilder(name1);// 添加容器
sBuilder1.append("(");
Class[] clazzPrams1 = method.getParameterTypes();// 返回描述了此
// Method
// 對象所表示的方法的形參類型
for (Class clazzPram1 : clazzPrams1) {
sBuilder1.append(clazzPram1.getName());
}
sBuilder1.append(")");
System.out.println(sBuilder1.toString());
}
System.out
.println("-----------begin create instance object-----------");
// 創建InvocationHandler的實例對象
Constructor constructor1 = clazzProxy1
.getConstructor(InvocationHandler.class);
// 第一種方法 創建MyInvocationHandler1並實現InvocationHandler接口
class MyInvocationHandler1 implements InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return null;
}
}
Collection proxy1 = (Collection) constructor1
.newInstance(new MyInvocationHandler1());
// 第二種創建方法:用匿名內部類
Collection proxy2 = (Collection) constructor1
.newInstance(new InvocationHandler() {
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
return null;
}
});
final ArrayList al = new ArrayList();
Collection proxy3 = (Collection) getProxy(al,new MyAdvice());
// proxy3.add("abc");
// proxy3.add("bcd");
// proxy3.add("cde");
System.out.println(proxy3.size());
}
}
// //第三種創建的方法:使用newProxyInstance方法 (抽取方法)
private static Object getProxy(final Object target, final Advice advice) {
Object proxy3 = Proxy.newProxyInstance(
target.getClass().getClassLoader(),
// new Class[]{Collection.class},
target.getClass().getInterfaces(),
new InvocationHandler() {
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
/*
* long beginTime = System.currentTimeMillis(); Object
* retVal = method.invoke(target, args); long endTime =
* System.currentTimeMillis();
*
* System.out.println(method.getName() + " 運行時間" +
* (endTime - beginTime)); return retVal;
*/
advice.beforeMethod(method);
Object retVal = method.invoke(target, args);
advice.afterMethod(method);
return retVal;
}
});
return proxy3;
}
}
</strong></span>