-
Notifications
You must be signed in to change notification settings - Fork 52
8. 有条件的DI
有些时候我们想要满足xxx条件才把一个类注册到容器里面。比如如何切换Services,如果是Spring,可以根据条件注册Bean和Configuration。所以我参考Spring的条件注解也在我的Autofac.Annotation框架中也实现了以下注解:
注解 | 使用方式 | 备注 |
---|---|---|
Conditional | 打在class或者方法上面 | 条件加载,自定义实现的 |
ConditionOnBean | 打在标有Bean注解的方法上面 | 条件加载 |
ConditionOnMissingBean | 打在标有Bean注解的方法上面 | 条件加载 |
ConditionOnClass | 打在class或者(含有Bean注解方法)上面 | 条件加载 |
ConditionOnMissingClass | 打在class或者(含有Bean注解方法)上面 | 条件加载 |
ConditionOnProperty | 打在class或者方法上面 | 条件加载 |
ConditionOnProperties | 打在class或者方法上面 | 条件加载 |
DependsOn | 可以配合Bean和Component使用 | A的实例化依赖另一个B的实例化,但是A并不需要持有一个B的对象 |
下面来讲讲使用方法:
这个注解接受一个实现了ICondition接口的Type类型的参数。
首先我们定义一个class实现ICondition接口的ShouldSkip方法,下面的类的意思看注释应该可以明白:
public class Test10Condition : ICondition
{
/// <summary>
/// 只有当 windows 系统下才被注册
/// </summary>
/// <param name="context"></param>
/// <param name="metadata"></param>
/// <returns>返回true代表不满足条件,那就不会被注册到容器</returns>
public bool ShouldSkip(IComponentRegistryBuilder context, object metadata)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
//是linux系统 就不注册
return true;
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
//是mac系统 也不注册
return true;
}
//是windows系统 那就注册
return false;
}
}
下面我们来使用上面的条件用Conditional注解打在方法上面,这个条件表明了只有在windows平台才会将Test10Model1注册到容器中
[AutoConfiguration]
public class Test10Config
{
[Bean]
[Conditional(typeof(Test10Condition))]
public Test10Model1 getTest10Model1()
{
Console.WriteLine("registered Test10Model1");
return new Test10Model1();
}
}
上面的例子是结合Bean注解一起使用,Conditional注解还可以打在class上面,结合Compoment或者AutoConfiguration注解来实现满足条件才注册!
这2个注解是只能配合Bean注解一起使用,且只能打在方法上面,不能打在class上面
- ConditionOnBean的意思是,如果指定的类已经被注册的话,我才要注册。
[AutoConfiguration]
public class Test10Config
{
[Bean]
[ConditionOnBean(typeof(Test10Model3))]
public Test10Model5 getTest10Model5()
{
Console.WriteLine("registered Test10Model5");
return new Test10Model5();
}
}
上面的代码的意思是,如果Test10Model3被注册的话,才会注册Test10Model5
- ConditionOnMissingBean的意思是,如果指定的类没被注册的话,我才要注册。
[AutoConfiguration]
public class Test10Config
{
[Bean]
[ConditionOnMissingBean(typeof(Test10Model1))]
public Test10Model3 getTest10Model3()
{
Console.WriteLine("registered Test10Model3");
return new Test10Model3();
}
}
上面的代码的意思是,如果Test10Model1没被注册的话,才会注册Test10Model3
这2个注解是配合Compoment或者AutoConfiguration,PointCut等注解一起使用,可以打在class和(含有Bean注解方法)上面,该注解的参数需要填入类的完整名称
什么叫类的完整名称?
详细可以参考issue:https://github.com/yuzd/Autofac.Annotation/issues/40 (感谢Decmoe47这位朋友的整理)
- ConditionOnClass的意思是如果当前运行环境存在指定的类,这个类不一定是Componet的话,就注册
[Bean]
[ConditionOnClass("Autofac.Annotation.Test.Test10Model2,Autofac.Configuration.Test")]
public Test10Model6 getTest10Model6()
{
//找的到class 所以可以注册Test10Model6
Console.WriteLine("registered Test10Model6");
return new Test10Model6();
}
- ConditionOnMissingClass的意思是如果当前运行环境不存在指定的类的话,就注册
[Bean]
[ConditionOnMissingClass("Autofac.Annotation.Test.test10.Test10Model2,xxxx")]
public Test10Model7 getTest10Model7()
{
//找不到class 所以注册Test10Model7
Console.WriteLine("registered Test10Model7");
return new Test10Model7();
}
这2个注解可以配合Bean,Compoment,AutoConfiguration,PointCut等注解一起使用,可以打在class和method上面
意思是,如果数据源(读取当前项目的appsettings.json)
- 指定的key对应的值为xxx时
- 或者不存在指定的key
就注册
appsettings.json
{
"onproperty": "on"
}
- 里面存在指定的key为xxx时就注册
[Bean]
[ConditionalOnProperty("onproperty", "on")]
public Test10Model8 getTest10Model8()
{
//因为配置文件onproperty的值为on 所以会注册
Console.WriteLine("registered Test10Model8");
return new Test10Model8();
}
- 或者不存在指定的key
[Bean]
[ConditionalOnProperty("onproperty1", matchIfMissing = true)]
public Test10Model10 getTest10Model10()
{
//由于配置文件里面没有onproperty1 所以会注册
Console.WriteLine("registered Test10Model10");
return new Test10Model10();
}
- 存在指定的key
[Bean]
[ConditionalOnProperty("onproperty1")]
public Test10Model10 getTest10Model10()
{
//由于配置文件有存在onproperty1 不管对应的值是什么,所以会注册
Console.WriteLine("registered Test10Model10");
return new Test10Model10();
}
当想要指定多个值同时满足的话就用ConditionOnProperties,道理是一样的~!
该注解可以配合Bean和Component注解一起使用,是用来表示一个 A的实例化依赖另一个B的实例化, 但是A并不需要持有一个B的对象
[Bean]
[DependsOn(typeof(Test12Bean4))]
public Test12Bean3 get13()
{
Debug.WriteLine("new Test12Bean3");
return new Test12Bean3 { Hello = "world" };
}
[Bean]
public Test12Bean4 get14()
{
Debug.WriteLine("new Test12Bean4");
result.Add("get14");
return new Test12Bean4 { Hello = "world" };
}
上面的意思是在需要加载Test12Bean3实例(还没)的时候,由于设置了DependsOn类Test12Bean4,先去加载Test12Bean4
[Component]
[DependsOn(typeof(Test12Bean8))] // 也支持配置类的全限定名称 [DependsOn("Autofac.Annotation.Test.test12.Test12Bean8,Autofac.Configuration.Test")]
public class Test12Bean7
{
public Test12Bean7()
{
//Console.WriteLine("然后我在加载")
}
public string Hello { get; set; }
}
[Component]
public class Test12Bean8
{
public Test12Bean8()
{
//Console.WriteLine("我先加载")
}
public string Hello { get; set; }
}
上面的意思是在需要加载Test12Bean7的实例的时候,先去加载Test12Bean8