这里写自定义目录标题
这2天,基于项目可维护性的考虑,要实现一套类似于Java Feign的类库,可以快速并且优雅的声明和调用API,当然,Feign都是接口声明,不考虑做接口实现,因此采用LinFu.DynamicProxy作为动态代理,来拦截所有Feign接口方法的调用。
LinFu.DynamicProxy介绍,可以参考这里,至于为啥不用Castle DynamicProxy,因为Castle依赖太多,基于简单考虑,就用LinFu吧。
关于LinFu.DynamicProxy 和 Castle DynamicProxy这2个库的动态代理使用,我写了2个Demo扔在某hub上了:
LinFu.DynamicProx的示例参考
Castle DynamicProxy的示例参考
-----这里是分割线,下面是特性说明-----
OK,了解Feign的同学都知道,有多少个api,就需要定义多少个Feign方法,每个方法都要特性声明,比如GetMapping、PostMapping等。
在DotNet里,可以通过Type.GetCustomAttributes,获取类上的所有特性声明。
那么,有没有类似Attribute.GetAllType这样的方法,来获取所有声明了某个特性的类呢?
很遗憾,查阅了一些资料,没有这样的方法,只能枚举所有的Type,去一个个调用Type.GetCustomAttributes,类似于:
foreach (Type type in customType.Assembly.GetTypes())
{
if (type.GetCustomAttributes(typeof(XxxAttribute), false).Length > 0)
{
yield return type;
}
}
与此同时,我也写了一些实验代码,测试一下Attribute的对象构造过程,结果是每调用一次GetCustomAttributes方法,就会创建一个全新的Attribute对象,实验代码简介:
先定义一个特性类:
public class BeinetAttribute : Attribute
{
public BeinetAttribute()
{
Console.WriteLine("BeinetAttribute构造函数执行了");
}
}
再定义一个使用了这个特性声明的类:
[Beinet]
public class BeinetDemo
{
}
下面是演示代码:
static void Main()
{
var type = typeof(BeinetDemo);
Console.WriteLine("第一次GetCustomAttributes:");
var atts1 = type.GetCustomAttributes(false);
Console.WriteLine("第二次GetCustomAttributes:");
var atts2 = type.GetCustomAttributes(false);
Console.WriteLine("2次读取对象是否相等:" + (atts1[0] == atts2[0]));
Console.Read();
}
执行结果如下,可以看到调用2次GetCustomAttributes,生成了2个对象:
第一次GetCustomAttributes:
BeinetAttribute构造函数执行了
第二次GetCustomAttributes:
BeinetAttribute构造函数执行了
2次读取对象是否相等:False
所以,如果特性里有些属性是可变的,要注意不要频繁GetCustomAttributes,可以只读取一次,然后缓存起来,比如下面的缓存代码:
static ConcurrentDictionary<Type, List<Attribute>> _typeAtts =
new ConcurrentDictionary<Type, List<Attribute>>();
public static List<Attribute> GetAttributes(Type type)
{
var ret = _typeAtts.GetOrAdd(type, typeInner =>
{
var result = typeInner.GetCustomAttributes(false);
return result.Select(item => (Attribute) item).ToList();
});
return ret;
}