C#通用的动态代理

C#通用的动态代理,第1张

目标框架Net Standard 20

安装引用类库SystemReflectionEmit  430

其他目标框架均适自带此类库,无需安装引用类库

原理:使用反射获取类、方法,将实现的代理类Invoke 通过SystemReflectionEmit改写到需要被改写的接口中,生成继承业务接口的中间类,调用中间类的接口则实现代理的任务。 

    /// <summary>

    /// 对应java的InvocationHandler接口

    /// 使用上应该是差不多的

    /// 注意点是,因为C#的Property的getset也是走这一个方法的

    /// 对于接口来说是全部代理,但是对于类只有虚方法代理

    /// </summary>

    public interface IInvocationHandler

    {

        object Invoke(object proxy, MethodInfo method, object[] args);

    } 

 public interface myIInvocationHandler

    {

        object m(string args, string arg2);

    }

    public class II : IInvocationHandler

    {

        public object Invoke(object proxy, MethodInfo method, object[] args)

        {

            foreach (object o in args)

            {

                ConsoleWriteLine(oToString());

            }

            ConsoleWriteLine($"hahahaha");

            return args[1];

        }

    }

    /// <summary>

    /// 缓存类,可以无视

    /// </summary>

    class ProxyTypeInfo

    {

        public TypeBuilder TypeBuilder;

        public int Count;

        public MethodInfo[] MethodInfos;

    }

    /// <summary>

    /// 代理类

    /// </summary>

    public static class DynamicProxy

    {

        private static readonly string AssemblyName = "DynamicProxyAssembly";

        private static readonly string ModuleName = "DynamicProxyModule";

        private static readonly string TypeName = "DynamicProxy";

        /// <summary>

        /// 因为有些方法的指令是需要拆箱装箱的

        /// </summary>

        private static readonly HashSet<Type> CanBox = new HashSet<Type>

    {

        typeof(int), typeof(uint),

        typeof(short), typeof(ushort),

        typeof(long), typeof(ulong),

        typeof(float), typeof(double),

        typeof(sbyte), typeof(byte),

        typeof(char),

        typeof(decimal),

    };

        private static readonly Dictionary<Type, ProxyTypeInfo> ProxyDict = new Dictionary<Type, ProxyTypeInfo>();

        private static TypeBuilder CreateDynamicTypeBuilder(Type type, Type parent, Type[] interfaces)

        {

            if (ProxyDictTryGetValue(type, out var info))

            {

                infoCount++;

            }

            else

            {

                ProxyDict[type] = info = new ProxyTypeInfo

                {

                    Count = 1

                };

            }

            //AssemblyBuilder ab =

            //      AssemblyBuilderDefineDynamicAssembly(

            //          aName,

            //          AssemblyBuilderAccessRun);

            var assemblyBuilder = AssemblyBuilderDefineDynamicAssembly(new AssemblyName(AssemblyName + typeName),

                AssemblyBuilderAccessRun);

            var moduleBuilder = assemblyBuilderDefineDynamicModule(ModuleName + typeName);

            return infoTypeBuilder = moduleBuilderDefineType(TypeName + typeName + infoCount,

                TypeAttributesPublic | TypeAttributesClass, parent, interfaces);

        }

        private static void ProxyInit(Type type, TypeBuilder typeBuilder, MethodInfo[] methodInfos,

            MethodInfo handlerInvokeMethodInfo)

        {

            //定义两个字段

            var handlerFieldBuilder =

                typeBuilderDefineField("_handler", typeof(IInvocationHandler), FieldAttributesPrivate);

            var methodInfosFieldBuilder =

                typeBuilderDefineField("_methodInfos", typeof(MethodInfo), FieldAttributesPrivate);

            //定义构造函数

            var constructorBuilder = typeBuilderDefineConstructor(MethodAttributesPublic, CallingConventionsStandard,

                new[] { typeof(IInvocationHandler), typeof(MethodInfo[]) });

            var ilCtor = constructorBuilderGetILGenerator();

            ilCtorEmit(OpCodesLdarg_0);

            ilCtorEmit(OpCodesCall,

                typeof(object)GetConstructor(new Type[0]) throw new Exception("不可能的错误:objectGetConstructor"));

            ilCtorEmit(OpCodesLdarg_0);

            ilCtorEmit(OpCodesLdarg_1);

            ilCtorEmit(OpCodesStfld, handlerFieldBuilder);

            ilCtorEmit(OpCodesLdarg_0);

            ilCtorEmit(OpCodesLdarg_2);

            ilCtorEmit(OpCodesStfld, methodInfosFieldBuilder);

            ilCtorEmit(OpCodesRet);

            for (var i = 0; i < methodInfosLength; i++)

            {

                var methodInfo = methodInfos[i];

                var parameterTypes = methodInfoGetParameters()Select(p => pParameterType)ToArray();

                var methodBuilder = typeBuilderDefineMethod(methodInfoName,

                    MethodAttributesPublic | MethodAttributesVirtual,

                    methodInfoCallingConvention, methodInfoReturnType, parameterTypes);

                var ilMethod = methodBuilderGetILGenerator();

                ilMethodEmit(OpCodesLdarg_0);

                ilMethodEmit(OpCodesLdfld, handlerFieldBuilder);

                ilMethodEmit(OpCodesLdarg_0);

                ilMethodEmit(OpCodesLdarg_0);

                ilMethodEmit(OpCodesLdfld, methodInfosFieldBuilder);

                ilMethodEmit(OpCodesLdc_I4, i);

                ilMethodEmit(OpCodesLdelem_Ref);

                ilMethodEmit(OpCodesLdc_I4, parameterTypesLength);

                ilMethodEmit(OpCodesNewarr, typeof(object));

                for (var j = 0; j < parameterTypesLength; j++)

                {

                    ilMethodEmit(OpCodesDup);

                    ilMethodEmit(OpCodesLdc_I4_S, (short)j);

                    ilMethodEmit(OpCodesLdarg_S, (short)(j + 1));

                    if (CanBoxContains(parameterTypes[j]))

                    {

                        ilMethodEmit(OpCodesBox, parameterTypes[j]);

                    }

                    ilMethodEmit(OpCodesStelem_Ref);

                }

                ilMethodEmit(OpCodesCallvirt, handlerInvokeMethodInfo);

                ilMethodEmit(CanBoxContains(methodInfoReturnType) OpCodesUnbox_Any : OpCodesCastclass,

                    methodInfoReturnType);

                ilMethodEmit(OpCodesRet);

            }

        }

        /// <summary>

        /// 通过接口创建动态代理

        /// </summary>

        public static T CreateProxyByInterface<T>(IInvocationHandler handler, bool userCache = true)

        {

            return (T)CreateProxyByInterface(typeof(T), handler, userCache);

        }

        public static object CreateProxyByInterface(Type type, IInvocationHandler handler, bool userCache = true)

        {

            if (!userCache || !ProxyDictTryGetValue(type, out var info))

            {

                var handlerInvokeMethodInfo = typeof(IInvocationHandler)GetMethod("Invoke")

                                              throw new Exception("不可能的错误:handlerInvokeMethodInfo");

                var typeBuilder = CreateDynamicTypeBuilder(type, null, new[] { type });

                var methodInfos = typeGetMethods();

                ProxyInit(type, typeBuilder, methodInfos, handlerInvokeMethodInfo);

                info = ProxyDict[type];

                if (infoCount == 1)

                {

                    infoMethodInfos = methodInfos;

                }

            }

            //Type t = infoTypeBuilderCreateTypeInfo();

            return ActivatorCreateInstance(infoTypeBuilderCreateTypeInfo(), handler, infoMethodInfos)

                                              throw new Exception("不同环境此处可能需要改写");

        }

        /// <summary>

        /// 通过类创建动态代理

        /// </summary>

        public static T CreateProxyByType<T>(IInvocationHandler handler, bool userCache = true)

        {

            return (T)CreateProxyByType(typeof(T), handler, userCache);

        }

        public static object CreateProxyByType(Type type, IInvocationHandler handler, bool userCache = true)

        {

            if (!userCache || !ProxyDictTryGetValue(type, out var info))

            {

                var handlerInvokeMethodInfo = typeof(IInvocationHandler)GetMethod("Invoke")

                                              throw new Exception("不可能的错误:handlerInvokeMethodInfo");

                var typeBuilder = CreateDynamicTypeBuilder(type, type, null);

                var methodInfos = typeGetMethods()Where(methodInfo => methodInfoIsVirtual || methodInfoIsAbstract)

                    ToArray();

                ProxyInit(type, typeBuilder, methodInfos, handlerInvokeMethodInfo);

                info = ProxyDict[type];

                if (infoCount == 1)

                {

                    infoMethodInfos = methodInfos;

                }

            }

            return ActivatorCreateInstance(infoTypeBuilderCreateTypeInfo(), handler, infoMethodInfos)

                                              throw new Exception("不同环境此处可能需要改写");

        }

    }

无法识别符号newproxyinstance是一个错误提示,表明你正在使用的程序出现了问题,可能是由于程序代码中出现了错误,或者是由于程序的环境变量出现了问题。为了解决这个问题,你可以检查程序代码,查看是否有任何错误,或者检查环境变量是否正确设置。此外,你还可以尝试重新安装程序,以确保程序正常运行。希望您能够解决这个问题。

3512 Destruction callbacks

<bean id="datasource"

class="orgapachecommonsdbcpBasicDataSource"

destroy-method="close">

<property name="driverClassName" value="$[]" />

</bean>

destroy-method指定了当要销毁bean datasource之前要做的 *** 作,也就是这个bean的收尾工作。

这里是指定了close()方法。

Closes and releases all idle connections that are currently stored in the connection pool associated with this data source

>

这篇先说明用法,下篇分析以下场景是如何将 Bean 注册进 IOC容器的。

这种用法在项目中是非常常见的,基本上是必有。我们来看下用法:

这样一个 Bean 就注册进 IOC 容器了,Bean 的名称默认是方法名,并且是不会转换大小写的,也就是假如你的方法名是 TestBean() ,那么 Bean 的名称就是 TestBean 。当然我们也可以使用 name 或者 value 指定 Bean 的名称,比如 @Bean(value = "testBean"),如果二者同时存在则会报错。

我们来看下其他属性:

autowireCandidate:默认值是 true 。如果设置为 false 的话,那么通过 byType 的方式获取 Bean 就会报错,当然我们可以使用 Resource 注解获取。

initMethod:在 Bean 实例化后调用的初始化方法,值是 Bean 类中的方法名。

destroyMethod:在 Bean 要销毁时调用的清理方法,值是 Bean 类中的方法名。

@Bean 注解只能定义在 @Configuration 类下吗? NO NO NO,它可以定义在任意能被 IOC 扫描的注解下,比如 @Component注解,至于区别,下篇再讲。

先讲普通用法:

深度用法:

ComponentScan 注解中有两个这样的属性:includeFilters 与 excludeFilters,前一个是只包含规则,后一个是排除包含规则,他们的值是一个 @Filter 注解的形式,Filter 中的 type 有 5 中类型,分别如下。

1、ANNOTATION

第一种是以注解的形式包含或不包含,比如:

这里边要配置useDefaultFilters = false 禁用默认规则,因为默认规则是扫描所有,配只包含就没用了。这里的意思只扫描 Configuration 注解。

2、ASSIGNABLE_TYPE

这种是包含我们给定的类型,不管是给定的类型和子类都会被包含进 IOC 容器。

然后我们发现 testBean 注册进去了,为什么我们不标注 @Component 这样的注解实例也会被注册进 IOC 呢?因为 ComponentScan 会扫描包下所有文件,只要符合我们定义的过滤规则,它就会将 Bean 注册进 IOC 容器中。

3、ASPECTJ

ASPECTJ 是使用 aspectj 表达式

4、REGEX

REGEX 是使用正则表达式

5、CUSTOM

这种呢就是我们 SpringBootApplication 注解用到的方式了,我来解释一下具体规则:这种方式是可以自己自定义扫描规则,它接受一个实现 TypeFilter 接口的类。

当它扫描类的时候扫描到了 TestBean,然后符合了我的匹配规则(也就是返回true)就注册进去了。

下面的例子中,我们直接看 Spring 源码的实现比较具有代表性一点。

我们点进 @EnableTransactionManagement 注解中,发现了这个 @Import(TransactionManagementConfigurationSelectorclass),它的作用就是将类导入,类会被注册进 IOC 容器中。

这个注解放置的位置要是 Spring 能扫描到的地方,不然 Spring 也不会主动去解析这个注解。

如果我们自己要使用注解的话,我们可以做个类似于 EnableTransactionManagement 的功能插拔式导入配置类,这样就可以实现动态开启一些 Bean 了。

我们还是来看下 TransactionManagementConfigurationSelector 这个类,看下它的继承关系发现它间接性的实现了 ImportSelector 接口,主要看它实现的这个方法:

这个方法的作用就是根据你返回的类全限定名(orgspringframeworkcontextannotationAutoProxyRegistrar)数组来创建 Bean 。

实现了 ImportSelector 的类也是需要使用 @Import 导入。

这个我们来看下 @MapperScan (orgmybatisspringannotation)导入的 MapperScannerRegistrar 发现它实现了 ImportBeanDefinitionRegistrar:

它的作用是拿到 BeanDefinitionRegistry Bean 的定义信息,然后往里面加 BeanDefinition 就会将相应的对象注册进去,它更深入的就不说了,实际上就是解析下注解属性,然后扫描相应的包下的类注册 Bean。我们自己搞个简单的。

这样就注册了一个 Bean 名称是 testBean 类型是 TestBean 类型的 Bean 了。

如果注册的是一个有参构造器呢?那就这样:

addConstructorArgValue 根据构造器参数的顺序去添加。

实现了 ImportBeanDefinitionRegistrar 的类也是需要使用 @Import 导入。

然后 TestBean 就注册进去了,打印的时候我们发现 Bean 的名称是 MyFactoryBean 的全限定名,但是它的类型是 TestBean 类型的,如果想要获取 MyFactoryBean 类型的 Bean 的话,通过 Bean 名称为 &myFactoryBean 就能获取到。

在我们的Spring Boot项目中,一般都是只扫描主类下的所有类,然后将一些被特定注解标注的类加载到IOC容器,但是如果我们将包分离,我们又如何更加方便的将其他包的类加载进来呢? spring boot提供了一种类似于Java的SPI(服务发现)机制springfactories,只要在resources目录下创建META-INF文件夹,再创建 springfactories文件,然后再里面配置

这样在导入当前包的就会自动扫描springfactories文件,解析后将里面的一些类加载到IOC容器中。具体的实现代码在spring-core的SpringFactoriesLoader类中。

这些就不讲了。

执行general_sys包下的init_method过程。

如果你给的这个东西能够执行的话,应该是在匿名块里面。

第一个参数lu_name_,是匿名块里面的变量。

第二个参数'&PKG',指需要执行的时候输入的变量,作为字符串传入。

第三个参数'New__',指传入New__这个字符串变量。

在目前的Java开发包中包含了对动态代理的支持,但是其实现只支持对接口的的实现。

其实现主要通过是javalangreflectProxy类和javalangreflectInvocationHandler接口。

Proxy类主要用来获取动态代理对象,InvocationHandler接口用来约束调用者实现,如下,HelloWorld接口定义的业务方法,HelloWorldImpl是HelloWorld接口的实现,HelloWorldHandler是InvocationHandler接口实现。代码如下:

业务接口:

public interface HelloWorld {

void sayHelloWorld() ;

}

业务接口实现:

public class HelloWorldImpl implements HelloWorld {

public void sayHelloWorld() {

Systemoutprintln("Hello World!");

}

}

InvocationHandler实现,需要在接口方法调用前后加入一部份处理工作,这里仅仅在方法调用前后向后台输出两句字符串,其代码如下:

import javalangreflectInvocationHandler;

import javalangreflectMethod;

public class HelloWorldHandler implements InvocationHandler {

//要代理的原始对象

private Object objOriginal;

/

构造函数。

@param obj 要代理的原始对象。

/

public HelloWorldHandler(Object obj) {

thisobjOriginal = obj ;

}

public Object invoke(Object proxy, Method method, Object[] args)

throws Throwable {

Object result ;

//方法调用之前

doBefore();

//调用原始对象的方法

result = methodinvoke(thisobjOriginal ,args);

//方法调用之后

doAfter();

return result ;

}

private void doBefore() {

Systemoutprintln("before method invoke!");

}

private void doAfter() {

Systemoutprintln("after method invoke!");

}

}

测试代码:

import javalangreflectInvocationHandler;

import javalangreflectProxy;

public class Test {

public static void main(String[] args) {

HelloWorld hw = new HelloWorldImpl();

InvocationHandler handler = new HelloWorldHandler(hw);

HelloWorld proxy = (HelloWorld) ProxynewProxyInstance(

hwgetClass()getClassLoader(),

hwgetClass()getInterfaces(),

handler);

proxysayHelloWorld();

}

}

�0�1 首先获取一个业务接口的实现对象;

�0�1 获取一个InvocationHandler实现,此处是HelloWorldHandler对象;

�0�1 创建动态代理对象;

�0�1 通过动态代理对象调用sayHelloWorld()方法,此时会在原始对象HelloWorldImpl sayHelloWorld()方法前后输出两句字符串。

运行测试类输出如下:

before method invoke!

Hello World!

after method invoke!

此处Test类中的方法调用代码比较多,在我们的实际应用中可以通过配置文件来来简化客户端的调用实现。另外也可以通过动态代理来实现简单的AOP

以上就是关于C#通用的动态代理全部的内容,包括:C#通用的动态代理、无法识别符号newproxyinstance、我想知道:Spring 配置bean需不需要加init-method和destroy-method加和不加有什么区别等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/9730172.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-01
下一篇 2023-05-01

发表评论

登录后才能评论

评论列表(0条)

保存