有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

为什么我们使用动态代理

A dynamic proxy class is a class that implements a list of interfaces specified at runtime such that a method invocation through one of the interfaces on an instance of the class will be encoded and dispatched to another object through a uniform interface. It can be used to create a type-safe proxy object for a list of interfaces without requiring pre-generation of the proxy class.Dynamic proxy classes are useful to an application or library that needs to provide type-safe reflective dispatch of invocations on objects that present interface APIs enter image description here

上面的图片是一个很好的例子,但为什么我们使用动态代理

有没有一个简单的例子,在现实世界中使用,为更多的感知


共 (4) 个答案

  1. # 2 楼答案

    link在代码中描述动态代理:

    public static class DynamicProxyGenerator  
    {  
        public static T GetInstanceFor<T>()  
        {  
            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;  
        }  
    }  
    
  2. # 3 楼答案

    一个常见的用例是Aspect-Oriented Programming,在该用例中,您寻求在多个组件之间应用公共功能,而不需要组件本身来实现该功能。在这些情况下,您可以使用动态代理以附加行为包装所有目标组件。这样做

    举几个例子:

    • 诸如Hibernate和entityframework之类的ORMs这样做是为了围绕代码优先设计提供持久性实现。核心域类是在不知道其持久性的情况下构建的,框架在启动时包装或扩展这些类以处理实际实现

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

  3. # 4 楼答案

    假设您有两个对象Car和Motorboat,分别实现接口CanDrive和CanFloat。现在,您需要第三个对象来实现这两个接口,并重用来自汽车和摩托艇的逻辑。在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());