一、简介
1.1 定义
给某一个对象提供一个代理,并由代理对象控制对真实对象的访问,代理模式是结构型设计模式的一种
代理模式详解
根据字节码文件的创建时机来分类,可以分为静态代理和动态代理
1.2 静态代理
在程序运行前就已经存在代理类的字节码文件,代理类和被目标类的关系在运行前就确定了
1.3 动态代理
代理类在程序运行期间优JVM根据反射等机制动态生成,在程序运行前并不存在代理类的字节码文件
为什么需要动态代理?
静态代理实现简单,且能够在不侵入原代码的情况下实现目标类的功能扩展。但是当场景稍微复杂的时候,静态代理存在如下缺点:
1、当需要对多个类代理时,由于代理类要实现和目标类一致的接口,有两种方式
(这里指的实现不同接口的目标类,如果需要扩展实现同一接口的目标类可以选择使用装饰器模式)
- 只维护一个代理类,实现所有的目标类接口,但是这样会导致代理类过于庞大
- 维护多个代理类,每个目标对象对应一个代理类,但是这样会导致代理类过多
2、当接口需要新增,删除,修改的时候,目标类和代理类都要同时修改,不易维护
动态代理可以解决上述静态代理的缺点
二、实现方式和原理
2.1 JDK动态代理
该方式为通过实现接口的方式
JDK动态代理主要设计两个类:java.lang.reflect.Proxy
和java.lang.reflect.InvocationHandler
2.1.1 实现示例
- 目标类接口:
public interface TargetInterface {
/**
* 原始方法1
*
* @return String
*/
String doSomething();
/**
* 原始方法2
*
* @return int
*/
int printNum();
}
- 目标类:
public class Target implements TargetInterface {
@Override
public String doSomething() {
System.out.println("doSomething");
return "doSomething";
}
@Override
public int printNum() {
System.out.println("printNum");
return 100;
}
}
- 代理类逻辑处理:(不是真正的代理类)
public class DynamicProxyHandler implements InvocationHandler {
/**
* 目标对象
*/
private final Object target;
public DynamicProxyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("do something before");
Object invoke = method.invoke(target, args);
System.out.println("do something after");
return invoke;
}
}
- 动态代理对象生成:
mport java.lang.reflect.Proxy;
public class ProxyTest {
public static void main(String[] args) {
//1、创建被代理的目标对象
Target target = new Target();
//2、创建代理类处理器对象
DynamicProxyHandler dynamicProxyHandler = new DynamicProxyHandler(target);
//3、创建代理类对象
//a.JDK会通过传入的参数信息动态地在内存中创建和.class文件等同的字节码
//b.然后会根据相应的字节码转换成对应的class
//c.最后创建代理类实例
TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), dynamicProxyHandler);
System.out.println("doSomething() call: " + proxy.doSomething());
System.out.println("------------------------");
System.out.println("proxy.printNum() call: " + proxy.printNum());
}
}
- 输出结果:
do something before
doSomething
do something after
doSomething() call: doSomething
------------------------
do something before
printNum
do something after
proxy.printNum() call: 100
2.1.2 原理说明
- 具体步骤
- 通过实现
InvovationHandler
接口创建自己的调用处理器 - 通过为
Proxy
类指定ClassLoader对象和一组Interface来创建动态代理类 - 通过反射机制获取动态代理类的构造函数,其唯一参数类型是
InvocationHandler
接口类型 - 通过构造函数创建动态代理类实例,调用处理器对象(
InvocationHandler
接口的实现类实例)作为参数传入
Proxy
类分析
public class Proxy implements java.io.Serializable {
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* 查找或者生成指定的代理类
*/
Class> cl = getProxyClass0(loader, intfs);
/*
* 获取参数为调用处理器接口的构造函数对象
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
final Constructor> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
/*
* 如果Class的作用域为私有,通过setAccessible设置可访问
*/
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
/*
* 创建代理类实例
*/
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);
}
}
}
/**
* 生成代理类
*/
private static Class> getProxyClass0(ClassLoader loader,
Class>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// 如果实现指定接口的代理类存在于指定加载器中,则直接返回缓存副本
// 否则通过ProxyClassFactory创建代理类
return proxyClassCache.get(loader, interfaces);
}
ProxyClassFactory
类生成代理类
简单步骤就是先生成类的字节码文件,再通过Proxy类的defineClass0本地方法生成字节码文件。具体实现代码可以查看Proxy类的静态内部类ProxyClassFactory源码。
- 字节码文件
System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
方法修改系统变量,可以保存生成的字节码文件
字节码文件:
package com.sun.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements TargetInterface {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m4;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String doSomething() throws {
try {
return (String)super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int printNum() throws {
try {
return (Integer)super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
- 代理类继承Proxy类,实现目标类接口(本例中对应
TargetInterface
接口),重写equals、hashCode、toString的方法 - 类和方法都被public final 修饰,所以类和方法只能使用,不能继承和重写
- 方法的实现最终会调用到代理调用处理器对象(本例中对应
DynamicProxyHandler
类实例)的invoke方法
2.2 CGLIB动态代理
CGLIB动态代理是基于ASM机制实现,通过生成业务类的子类作为代理类。
具体使用介绍可参考如下文章
Java 动态代理详解
三、参考文章
JAVA动态代理
Java 动态代理详解