代理模式&动态代理
什么是代理模式?
代理模式(Proxy Pattern)也称为委托模式,是结构型设计模式的一种。当无法或不想直接访问某个对象或访问某个对象存在困难时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口。
代理模式的UML类图

角色介绍
- ISubject:抽象主题类。该类的主要职责是声明真实主题与代理的共同接口方法,该类既可以是一个抽象类也可以是一个接口。
- RealSubject : 真实的主题类。该类也被称为被委托类或被代理类,该类定义了代理所表示的真实对象,由其执行具体的业务逻辑方法,而客户类则通过代理类简洁的调用真实主题类中定义的方法。
- ProxySubject : 代理类;该类也称为委托类或代理类,该类持有一个真实主题类的引用,在其所实现的接口方法中调用真实主题实现的方法执行,以此实现代理的作用。在代理者中,在拿到真是对象返回结果的同时,可以对结果做进一步的处理,以对真实对象进行保护
- Client :客户端。
简单实现&静态代理
我以我家猫主子Nimo日常生活看电视举例:Nimo想看电视,但是它无法操作电视,只有通过喵喵喵命令我去帮他做这些事情。
setp 1:定义一个(Nimo日常行为的)抽象主题接口。
public interface IWatchTV {
/**
* Nimo要看电视
*/
void powerOn();
/**
* Nimo不想看电视了
*/
void powerOff();
/**
* Nimo想换个节目
*/
void nextChanel();
/**
* Nimo觉得上个节目好看
*/
void previousChanel();
}
step 2: 一个真实的主题实现类(NimoSubjectIml)
public class NimoSubjectIml implements IWatchTV {
@Override
public void powerOn() {
println("好无聊,我要看电视!");
}
@Override
public void powerOff() {
println("好无聊,我要睡觉!");
}
@Override
public void nextChanel() {
println("我不喜欢这个节目!");
}
@Override
public void previousChanel() {
println("我要看上个节目");
}
}
step 3:实现一个代理类(铲屎官)
public class MarginProxy implements IWatchTV {
//持有一个具体主题类的引用
private IWatchTV mRealSubject;
//注入具体主题类对象
public MarginProxy(IWatchTV realSubject) {
this.mRealSubject = realSubject;
}
@Override
public void powerOn() {
mRealSubject.powerOn();
}
@Override
public void powerOff() {
mRealSubject.powerOff();
}
@Override
public void nextChanel() {
mRealSubject.nextChanel();
}
@Override
public void previousChanel() {
mRealSubject.previousChanel();
}
}
客户类使用:
public class ProxyClient {
public static void main(String[] args) {
IWatchTV nimoSubject = new NimoSubjectIml();
IWatchTV proxy = new MarginProxy(nimoSubject);
//我帮猫主子打开电视
proxy.powerOn();
//我帮猫主子换个节目
proxy.nextChanel();
//我帮猫主子换回上个节目
proxy.previousChanel();
//我给猫主子关了电视
proxy.powerOff();
}
}
可以看到,代理模式很简单,主要是一种委托机制,真实对象将方法的执行委托给代理对象,这就是为什么代理模式也成为委托模式的原因。
代理模式分为静态代理、动态代理这两种。上面的例子即为静态代理。
- 静态代理:如上demo那样,代理者的代码在程序运行前由我们实现再对其进行编译,也就是说,我们的代码在运行前代理类class编译文件已经存在;
- 动态代理:与静态代理相关,通过反射机制动态地生成代理者的对象,也就是说在code阶段代理者压根不存在,我们也不需要知道被代理的对象是谁,被代理者我们将会在执行阶段决定。
动态代理
java提供了一个动态代理接口,java.lang.reflect.InvocationHandler。动态代理实现步骤如下:
step 1 :同静态代理,需要一个抽象主题类(猫主子的日常生活)。
public interface IUsualLife {
/**
* 吃饭(我给它喂小鱼干)
*/
void eatting();
/**
* 换衣服(我给它穿衣服)
*/
void dress();
/**
* 散步(我带着它巡视自己的江山)
*/
void walk();
}
step 2 :同静态代理,一个具体真实的被代理主题实现类(我的另一只猫主子小美)。
public class PrettySubjectIml implements IUsualLife {
@Override
public void eatting() {
println("小美饿了要吃小鱼干!");
}
@Override
public void dress() {
println("小美吃饱喝足了要穿新衣服!");
}
@Override
public void walk() {
println("小美要去巡视自己的江山!");
}
}
step 3:实现InvocationHandler,定义自己的代理类方法执行处理器。
public class DynamicHandler implements InvocationHandler {
//被代理对象的引用
private Object mRealSubject;
public DynamicHandler(Object realSubject) {
this.mRealSubject = realSubject;
}
/**
* 动态注入被代理对象
*
* @param realSubject
*/
public void setmRealSubject(Object realSubject) {
this.mRealSubject = realSubject;
}
/**
* 动态生成代理类/委托类
*
* @param <T>
* @return
*/
public <T> T getProxy() {
return (T) Proxy.newProxyInstance(mRealSubject.getClass().getClassLoader(),
mRealSubject.getClass().getInterfaces(),
this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
onStart();
Object result = method.invoke(mRealSubject, args);
onSuccess();
return result;
}
/**
* 在方法执行前做一些操作
*/
private void onStart() {
}
/**
* 在方法执行后做一些操作
*/
private void onSuccess() {
}
}
在这里,我们通过setter动态注入被代理对象,通过getProxy()获取被代理对象的代理者,我们在invoke方法中,通过反射调用具体的被代理类的方法,也就是真实的方法。通过上面一系列方法,我们不再关心我们的代理者的具体实现是什么,代理者代理谁。
在客户类中使用:
public class ProxyClient {
public static void main(String[] args) {
//实例化真实主题类
IWatchTV nimoSubject = new NimoSubjectIml();
//实例化代理类方法执行器
DynamicHandler handler = new DynamicHandler(nimoSubject);
//动态生成代理者
IWatchTV proxy = handler.getProxy();
//通过代理者执行真实对象的具体方法。
proxy.powerOn();
proxy.nextChanel();
proxy.previousChanel();
proxy.powerOff();
//实例化另一只猫主子小美
IUsualLife pretty = new PrettySubjectIml();
//代理小美
handler.setRealSubject(pretty);
//生成另一个代理者(假设我有一个女朋友带着它)
IUsualLife usualLifeProxy = handler.getProxy();
usualLifeProxy.eatting();
usualLifeProxy.dress();
usualLifeProxy.walk();
}
}
通过上面的例子可知,动态代理通过一个代理类来代理N多个被代理类,其实质是对代理者与被代理者进行解耦,是其两者没有直接的耦合关系。相对而言,静态代理只能为给定接口下的实现类做代理,如果接口不同就需要重新定义不同的代理类。由此可见,动态代理跟符合面向对象原则。
动态代理看着简单又方便,但是,动态代理到底是如何实现动态代理的呢?他的代理类在哪里?代理类如何生成的呢?我们一起走进本期《走近科学》,一起揭开“不见代理者却可以动态代理”的神秘面纱;
动态代理原理探究
我们点进Proxy.newProxyInstance(…)定位到Proxy中的newProxyInstance方法中
代码块1:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
//检查InvocationHandler
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
//***省略检查代码***
/*
* Look up or generate the designated proxy class.
* (在缓存中)查找或生成指定的代理类
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
//...省略若干行检查代码...
//返回代理者实例
return cons.newInstance(new Object[]{h});
//...省略若干行try - catch...
}
可以看到,这个方法做了两个个重要的事情:
- 在缓存中查找或生成指定的代理类;
- 实例化代理类对象并返回其实例。
有了代理类的class,我们就可以通过反射拿到其实例,那么,代理类class到底是如何生成的呢,我们接着点进getProxyClass0():
代码块2:
/**
* Generate a proxy class. Must call the checkProxyAccess method
* to perform permission checks before calling this.
*/
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
return proxyClassCache.get(loader, interfaces);
}
这个方法中,只做了两件事:
- 接口实现数量是否超过了65535个;
- 返回代理类class,通过proxyClassCache.get()可以看出,我们的代理类 class 与缓存相关,这也就解释了一个问题,“代理类在哪里呢”,代理类class存在缓存中
接着点进 proxyClassCache.get(loader, interfaces)方法定位到WeachCache中:
代码块3:
public V get(K key, P parameter) {
//...省略一些校验代码...
// create subKey and retrieve the possible Supplier<V> stored by that
// subKey from valuesMap
//生成代理类class并生成对应的缓存key
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
//使用上面生成的key从缓存中取出其代理类class的持有者
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
//检查从缓存中获取到的代理类持有者是否存在,如果不存在则创建新的持有者然后存入缓存中,然后从持有者中获取代理类class并返回
while (true) {
if (supplier != null) {
// supplier might be a Factory or a CacheValue<V> instance
V value = supplier.get();
if (value != null) {
return value;
}
}
// else no supplier in cache
// or a supplier that returned null (could be a cleared CacheValue
// or a Factory that wasn't successful in installing the CacheValue)
// lazily construct a Factory
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
// successfully installed Factory
supplier = factory;
}
// else retry with winning supplier
} else {
if (valuesMap.replace(subKey, supplier, factory)) {
// successfully replaced
// cleared CacheEntry / unsuccessful Factory
// with our Factory
supplier = factory;
} else {
// retry with current supplier
supplier = valuesMap.get(subKey);
}
}
}
}
这个方法主要做了两件事:
- 创建代理类class并创建对应的缓存key;
- 创建代理类class持有者并存入缓存;
但是还是迄今为止还是不知道代理类class是如何生成的,我们接着点进 Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter))的关键方法apply()中
代码块4:
@FunctionalInterface
public interface BiFunction<T, U, R> {
/**
* Applies this function to the given arguments.
*
* @param t the first function argument
* @param u the second function argument
* @return the function result
*/
R apply(T t, U u);
/**
* Returns a composed function that first applies this function to
* its input, and then applies the {@code after} function to the result.
* If evaluation of either function throws an exception, it is relayed to
* the caller of the composed function.
*
* @param <V> the type of output of the {@code after} function, and of the
* composed function
* @param after the function to apply after this function is applied
* @return a composed function that first applies this function and then
* applies the {@code after} function
* @throws NullPointerException if after is null
*/
default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t, U u) -> after.apply(apply(t, u));
}
}
点进来发现是一个抽象接口,,我们返回在apply处右键

接着在实现类列表中找到我们的目标类:

然后我们就到了Proxy中内部类ProxyClassFactory的apply方法中:
代码块5:
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
//1.一些接口校验
for (Class<?> intf : interfaces) {
/*
* Verify that the class loader resolves the name of this
* interface to the same Class object.
* 1.1 确认类加载器是否把接口正确的加载
*/
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");
}
/*
* Verify that the Class object actually represents an
* interface.
* 1.2 检查该接口是否确实为接口
*/
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
/*
* Verify that this interface is not a duplicate.
* 1.3 检查是否重复实现
*/
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
String proxyPkg = null; // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
/*
* Record the package of a non-public proxy interface so that the
* proxy class will be defined in the same package. Verify that
* all non-public proxy interfaces are in the same package.
* 2.检查接口是否公共可访问的
*/
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
//获得代理类包名
if (proxyPkg == null) {
// if no non-public proxy interfaces, use com.sun.proxy package
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
/*
* Choose a name for the proxy class to generate.
* 得到代理类class数量(从0开始),可能会有多个代理类,然后得到代理类class名
*/
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* Generate the specified proxy class.
* 生成代理类的二进制数据
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
//返回代理类class
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
/*
* A ClassFormatError here means that (barring bugs in the
* proxy class generation code) there was some other
* invalid aspect of the arguments supplied to the proxy
* class creation (such as virtual machine limitations
* exceeded).
*/
throw new IllegalArgumentException(e.toString());
}
}
}
这个方法里做了很多事情:
- 校验代理类需要实现的接口;
- 根据一定的规则生成代理类唯一类名;
- 生成代理类字节数组;
- 生成并返回代理类class
我们在运行时,通过在proxy获取实例加断点可以发现,prox实例类名都是**"$Proxy"+"n”**的形式,就是这里说的第二点,生成的唯一的class名字,以防止重复;
我们再点进ProxyGenerator.generateProxyClass()方法:
代码块6:
public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
final byte[] var4 = var3.generateClassFile();
if (saveGeneratedFiles) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
try {
int var1 = var0.lastIndexOf(46);
Path var2;
if (var1 > 0) {
Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));
Files.createDirectories(var3);
var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
} else {
var2 = Paths.get(var0 + ".class");
}
Files.write(var2, var4, new OpenOption[0]);
return null;
} catch (IOException var4x) {
throw new InternalError("I/O exception saving generated file: " + var4x);
}
}
});
}
return var4;
}
可以看到,这里先这样,再这样,然后这样,再那样,最后那样,就生成了代理类class二进制数组,其实我不懂这一块儿,哈哈哈哈哈哈。。。
我们返回再点进defineClass0()方法:
代码块7:
private static native Class<?> defineClass0(ClassLoader loader, String name,
byte[] b, int off, int len);
尴尬的发现,这是一个native方法。不过还是可以知道,在这个native方法中,通过代理类二进制数组生成了class并返回了。。。。
即使有了生成了代理类,到这一步,我们还是不知道代理类是什么样子的。怎么办呢?
山人自有妙计🤓
我们回头看代码块5中:
//生成proxy class二进制数组
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
看到这个字节数组,心中突然产生了一个大胆的想法🤓
既然有了字节数组,那不就可以写在本地了嘛!!!
于是我从源码里拷贝出这部分代码,自己写了个工具类
public class ProxyUtils {
public static void writeProxyClass(String path,String proxyName,Class realSubjectClazz){
//得到proxy class字节数组
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, realSubjectClazz.getInterfaces(), accessFlags);
String fullPathName = path+proxyName+".class";
//写到本地
try {
FileOutputStream fos = new FileOutputStream(fullPathName);
fos.write(proxyClassFile);
fos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
然后在client中调用
代码块8
public class ProxyClient {
public static void main(String[] args) {
//实例化真实主题类
IWatchTV nimoSubject = new NimoSubjectIml();
//实例化代理类方法执行器
final DynamicHandler handler = new DynamicHandler(nimoSubject);
//动态反射生成代理者
IWatchTV proxy = handler.getProxy();
//通过代理者执行真是对象的具体方法。
proxy.powerOn();
proxy.nextChanel();
proxy.previousChanel();
proxy.powerOff();
//实例化另一只猫主子小美
IUsualLife pretty = new PrettySubjectIml();
//代理小美
handler.setRealSubject(pretty);
//生成另一个代理者(假设我有一个女朋友带着它)
IUsualLife usualLifeProxy = handler.getProxy();
usualLifeProxy.eatting();
usualLifeProxy.dress();
usualLifeProxy.walk();
//--调用工具类方法将动态生成的代理类保存到本地,这里传入nimoSubject生成
//--nimoSubject的代理类
ProxyUtils.writeProxyClass("path","NimoProxy",nimoSubject.getClass());
}
}
于是,我们就在目标路径中得到代理类class文件,然后打开后(需要注意class文件是二进制的,直接打开看不了的,可以反编译或者IDEA or androidStudio打开看)得到代理类的代码:
代码块9
public final class $Proxy0 extends Proxy implements IWatchTV {
private static Method m1;
private static Method m6;
private static Method m2;
private static Method m4;
private static Method m3;
private static Method m5;
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 void nextChanel() throws {
try {
super.h.invoke(this, m6, (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 void previousChanel() throws {
try {
super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void powerOn() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void powerOff() throws {
try {
super.h.invoke(this, m5, (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);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m6 = Class.forName("main.design_pattern.proxy_pattern.simple.IWatchTV").getMethod("nextChanel");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m4 = Class.forName("main.design_pattern.proxy_pattern.simple.IWatchTV").getMethod("previousChanel");
m3 = Class.forName("main.design_pattern.proxy_pattern.simple.IWatchTV").getMethod("powerOn");
m5 = Class.forName("main.design_pattern.proxy_pattern.simple.IWatchTV").getMethod("powerOff");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
- 首先可以看到,代理类继承了Proxy,同时它和被代理类果然实现了共同的接口IwatchTV,;
- 我们再看一下静态区域,静态的Method变量和static区域熟悉的代码,通过反射获取到接口的方法并赋给Method变量;
- 在实现方法中调用被代理对象的方法。
在实现方法中我们以nextChanel()方法举例, super.h.invoke(this, m6, (Object[])null)这行代码看似标准的反射调用类的方法。只是,是通过super.h.invoke(),那么h是什么呢,我们再次点开其父类Proxy查看它的源码:
代码块10
public class Proxy implements java.io.Serializable {
//...忽略部分代码...
protected InvocationHandler h;
/**
* Prohibits instantiation.
*/
private Proxy() {
}
protected Proxy(InvocationHandler h) {
Objects.requireNonNull(h);
this.h = h;
}
//...忽略部分代码...
可以看到它的成员变量InvocationHandler h和它的构造函数,再回头看看代理类(代码块9)的构造函数
还有代码块1中代理类的实例化传入的参数 return cons.newInstance(new Object[]{h});还有上面动态代理实现step3中的DynamicHandler实现了InvocationHandler,一切的源头newProxyInstance()传入的参数,是不是所有的线索都明了了,所有的片段终于凑成了一幅完整的篇章,一切都拨云见日豁然开朗了!
- 代理类中持有InvocationHandler的引用;
- 我们自己实现了InvocationHandler存在Dynamic,并实现其方法invoke并在此方法中调用真实对象的方法;
- 在实例化代理类的时候的将我们自己的InvocationHandler实例注入,这样在代理类中接口实现的方法中,就可以通过InvocationHandler来调用真实对象的方法了。
到此处,动态代理的原理的分析也就到此结束了。
最后附上我的两位猫主子

本文深入剖析动态代理原理,从静态代理对比引入,详细解读Java动态代理的实现机制,包括InvocationHandler接口应用、Proxy类作用及代理类生成过程。
1242

被折叠的 条评论
为什么被折叠?



