摘要
相比于静态代理,动态代理避免了开发人员编写各个繁锁的静态代理类,只需简单地指定一组接口及目标类对象就能动态的获得代理对象。
代理模式

使用代理模式必须要让代理类和目标类实现相同的接口,客户端通过代理类来调用目标方法,代理类会将所有的方法调用分派到目标对象上反射执行,还可以在分派过程中添加"前置通知"和后置处理(如在调用目标方法前校验权限,在调用完目标方法后打印日志等)等功能。
使用动态代理的五大步骤
1.通过实现InvocationHandler接口来自定义自己的InvocationHandler;
2.通过Proxy.getProxyClass获得动态代理类
3.通过反射机制获得代理类的构造方法,方法签名为getConstructor(InvocationHandler.class)
4.通过构造函数获得代理对象并将自定义的InvocationHandler实例对象传为参数传入
5.通过代理对象调用目标方法
动态代理的使用
例1(方式一)
public class MyProxy {
public interface IHello{
void sayHello();
}
static class Hello implements IHello{
public void sayHello() {
System.out.println("Hello world!!");
}
}
//自定义InvocationHandler
static class HWInvocationHandler implements InvocationHandler{
//目标对象
private Object target;
public HWInvocationHandler(Object target){
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("------插入前置通知代码-------------");
//执行相应的目标方法
Object rs = method.invoke(target,args);
System.out.println("------插入后置处理代码-------------");
return rs;
}
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetExc eption, InstantiationException {
//生成$Proxy0的class文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
//获取动态代理类
Class proxyClazz = Proxy.getProxyClass(IHello.class.getClassLoader(),IHello.class);
//获得代理类的构造函数,并传入参数类型InvocationHandler.class
Constructor constructor = proxyClazz.getConstructor(InvocationHandler.class);
//通过构造函数来创建动态代理对象,将自定义的InvocationHandler实例传入
IHello iHello = (IHello) constructor.newInstance(new HWInvocationHandler(new Hello()));
//通过代理对象调用目标方法
iHello.sayHello();
}
}
</div>
输出:
------插入前置通知代码-------------
Hello world!!
------插入后置处理代码-------------
Proxy类中还有个将2~4步骤封装好的简便方法来创建动态代理对象,其方法签名为:newProxyInstance(ClassLoader loader,Class<?>[] instance, InvocationHandler h),如下例:
(方式二)
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//生成$Proxy0的class文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
IHello ihello = (IHello) Proxy.newProxyInstance(IHello.class.getClassLoader(), //加载接口的类加载器
new Class[]{IHello.class}, //一组接口
new HWInvocationHandler(new Hello())); //自定义的InvocationHandler
ihello.sayHello();
}
</div>
输出结果一样.
下面以newProxyInstance方法为切入点来剖析代理类的生成及代理方法的调用
(为了篇幅整洁去掉了次要的代码)
public static Object newProxyInstance(ClassLoader loader,
Class<!--?-->[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
if (h == null) { //如果h为空直接抛出异常,所以InvocationHandler实例对象是必须的
throw new NullPointerException();
}
//对象的拷贝,暂不知道这里拷贝下的意义是啥?
final Class<!--?-->[] intfs = interfaces.clone();
//一些安全的权限检查
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
//产生代理类
Class<!--?--> cl = getProxyClass0(loader, intfs);
//获取代理类的构造函数对象
//参数constructorParames为常量值:private static final Class<!--?-->[] constructorParams = { InvocationHandler.class };
final Constructor<!--?--> cons = cl.getConstructor(constructorParames);
final InvocationHandler ih = h;
//根据代理类的构造函数对象来创建代理类对象
return newInstance(cons, ih);
}
</div>
这段代码就是对代理类对象的创建,就是对例1中34~38行封装,其中getProxyClass0就是生成代理类的方法
getProxyClass0方法剖析
private static Class<!--?--> getProxyClass0(ClassLoader loader,
Class<!--?-->... interfaces) {
//接口数不得超过65535个
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
//代理类缓存,如果缓存中有代理类了直接返回,否则将由ProxyClassFactory创建代理类
return proxyClassCache.get(loader, interfaces);
}
</div>
看看ProxyClassFactory是怎样生成代理类的?
private static final class ProxyClassFactory
implements BiFunction<classloader, class<?="">[], Class<!--?-->>
{
//统一代理类的前缀名都以$Proxy开关
private static final String proxyClassNamePrefix = "$Proxy";
//使用唯一的编号给作为代理类名的一部分,如$Proxy0,$Proxy1等
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@Override
public Class<!--?--> apply(ClassLoader loader, Class<!--?-->[] interfaces) {
Map<class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<!--?--> intf : interfaces) {
//验证指定的类加载器(loader)加载接口所得到的Class对象(interfaceClass)是否与intf对象相同
Class<!--?--> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
//验证该Class对象是不是接口
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
// 验证该接口是否重复了
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
//声明代理类所在包
String proxyPkg = null;
/*验证你传入的接口中是否有非public接口,只要有一个接口是非public的,那么这些接口都必须在同一包中
这里的接口修饰符直接影响到System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true")所生成
的代理类的路径,往下看!!*/
for (Class<!--?--> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
String name = intf.getName();
int n =

