1. 什么是動(dòng)態(tài)代理顾瞪?
代理模式為一種設(shè)計(jì)模式,其目的就是為其他對(duì)象提供一個(gè)代理以控制對(duì)某個(gè)真實(shí)對(duì)象的訪問抛蚁。代理類負(fù)責(zé)為委托類預(yù)處理消息陈醒,過濾消息并轉(zhuǎn)發(fā)消息,以及進(jìn)行消息被委托類執(zhí)行后的后續(xù)處理
動(dòng)態(tài)代理的意思就是在程序運(yùn)行時(shí)生成委托類的代理類來實(shí)現(xiàn)增強(qiáng)的功能瞧甩。
2. 動(dòng)態(tài)代理有哪些實(shí)現(xiàn)方式钉跷?
2.1 jdk本身自帶的動(dòng)態(tài)代理類。
由JVM在程序運(yùn)行時(shí)生成代理類肚逸,使用java反射機(jī)制爷辙。
- demo
public class MyInvocationHandler implements InvocationHandler {
private Object target;
// 通過此方法可以生成委托類的代理類,原理通過傳入的委托類的對(duì)象的類加載器生成一個(gè)代理類對(duì)象
public Object bind(Object target, Class[] interfaces) {
this.target = target;
//取得代理對(duì)象,通過被代理對(duì)象的類加載器朦促,生成代理對(duì)象
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
interfaces, this);
}
// 通過此方法增強(qiáng)委托類中的方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("增強(qiáng)內(nèi)容前膝晾!");
Object invoke = method.invoke(target, args);
System.out.println("增強(qiáng)內(nèi)容后!");
return invoke;
}
}
--------------------------------------------------------------------------------------------------------------------------------------------
public static void main(String[] args) {
MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
TestInterface test = new com.thunisoft.casespace.common.dtdl.Test();
TestInterface bind =(TestInterface) myInvocationHandler.bind(test, new Class[]{TestInterface.class});
bind.test();
bind.test2();
}
-
newProxyInstance源碼分析:
···
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
// 調(diào)用處理程序(實(shí)現(xiàn)InvocationHandler接口的實(shí)現(xiàn)類)不為空
Objects.requireNonNull(h);
// 拷貝對(duì)象务冕,設(shè)置成為常量
final Class<?>[] intfs = interfaces.clone();
// 調(diào)用java安全管理器
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}/* * Look up or generate the designated proxy class * 查找或者生成指定的代理類,該步驟會(huì) 查詢 proxyClassCache 代理類緩存中是否存在該指定類型的代理類血当,如果不存在則生成 */ Class<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. * 使用指定的調(diào)用處理程序調(diào)用其構(gòu)造函數(shù)。 */ try { if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } // 調(diào)用有參的構(gòu)造函數(shù)生成類構(gòu)造器 final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); } // 創(chuàng)建對(duì)象 return cons.newInstance(new Object[]{h}); } catch (IllegalAccessException|InstantiationException e) { throw new InternalError(e.toString(), e); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString(), t); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString(), e); }
}
···
2.2 ASM、cglib(基于 ASM)臊旭、Javassist 等方式
該方式后續(xù)在補(bǔ)充落恼。
AccessibleObject.setAccessible方法,可以在運(yùn)行時(shí)更改類屬性的作用域,可以通過他繞開類的api訪問控制.