为什么我们使用动态代理

动态代理类是实现在运行时指定的接口列表的类,这样通过类的实例上的一个接口的方法调用将被编码并通过统一接口分派给另一个对象。 它可用于为接口列表创建类型安全的代理对象,而无需预生成代理类。动态代理类对需要在对象上提供类型安全的reflection调度调度的应用程序或库非常有用提供接口API 在此处输入图像描述

上面的图片很好,但为什么我们使用动态代理?

有没有一个简单的例子可以在现实世界中使用,以获得更多感知?

此链接描述代码中的动态代理:

public static class DynamicProxyGenerator { public static T GetInstanceFor() { Type typeOfT = typeof(T); var methodInfos = typeOfT.GetMethods(); AssemblyName assName = new AssemblyName("testAssembly"); var assBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assName, AssemblyBuilderAccess.RunAndSave); var moduleBuilder = assBuilder.DefineDynamicModule("testModule", "test.dll"); var typeBuilder = moduleBuilder.DefineType(typeOfT.Name + "Proxy", TypeAttributes.Public); typeBuilder.AddInterfaceImplementation(typeOfT); var ctorBuilder = typeBuilder.DefineConstructor( MethodAttributes.Public, CallingConventions.Standard, new Type[] { }); var ilGenerator = ctorBuilder.GetILGenerator(); ilGenerator.EmitWriteLine("Creating Proxy instance"); ilGenerator.Emit(OpCodes.Ret); foreach (var methodInfo in methodInfos) { var methodBuilder = typeBuilder.DefineMethod( methodInfo.Name, MethodAttributes.Public | MethodAttributes.Virtual, methodInfo.ReturnType, methodInfo.GetParameters().Select(p => p.GetType()).ToArray() ); var methodILGen = methodBuilder.GetILGenerator(); if (methodInfo.ReturnType == typeof(void)) { methodILGen.Emit(OpCodes.Ret); } else { if (methodInfo.ReturnType.IsValueType || methodInfo.ReturnType.IsEnum) { MethodInfo getMethod = typeof(Activator).GetMethod(/span>"CreateInstance",new Type[]{typeof((Type)}); LocalBuilder lb = methodILGen.DeclareLocal(methodInfo.ReturnType); methodILGen.Emit(OpCodes.Ldtoken, lb.LocalType); methodILGen.Emit(OpCodes.Call, typeofype).GetMethod("GetTypeFromHandle")); )); methodILGen.Emit(OpCodes.Callvirt, getMethod); methodILGen.Emit(OpCodes.Unbox_Any, lb.LocalType); } else { methodILGen.Emit(OpCodes.Ldnull); } methodILGen.Emit(OpCodes.Ret); } typeBuilder.DefineMethodOverride(methodBuilder, methodInfo); } Type constructedType = typeBuilder.CreateType(); var instance = Activator.CreateInstance(constructedType); return (T)instance; } } 

一个常见的用例是面向方面编程 ,在这种情况下,您可以在多个组件中应用通用function,而无需组件本身来实现function。 在这些情况下,您可以使用动态代理来包装所有目标组件以及其他行为。 这样做

几个例子:

  • 诸如Hibernate和Entity Framework之类的ORM执行此操作以围绕代码优先设计提供持久性实现。 构建核心域类时不知道它们的持久性,并且框架在启动时包装或扩展这些类以处理实际的实现。

  • 使用日志记录或缓存等方面包装接口的所有成员。 例如,如果要记录ISomeInterface上的每个方法调用,您可以编写一个动态代理来查找所有接口方法,使用方法详细信息调用Log方法,然后将调用传递给实际的实现。

想象一下,你有两个物体Car和Motorboat分别实现CanDrive和CanFloat接口。 现在,您希望拥有第三个实现这两个接口的对象,并重用Car和Motorboat中的逻辑。 在Groovy,Ruby和Scala等语言中,您可以使用mixin解决这个问题。 然而,在Java中,没有这样的东西。 您当然可以使用例如适配器设计模式,但在许多情况下(特别是在构建框架时),动态代理很有用。 考虑使用cglib库的示例:

 CanDrive car = new Car(); CanFloat motorboat = new Motorboat(); net.sf.cglib.proxy.Mixin amphibian = net.sf.cglib.proxy.Mixin.create(new Object[] { car, motorboat }); TestCase.assertEquals("bzzz bzzz bzzz ...", ((CanFloat) amphibian)._float()); TestCase.assertEquals("pyr pyr pyr pyr ...", ((CanDrive) amphibian).drive());