• SpringBoot的注解注入功能移植到.Net平台(开源)


    最近在公司用java和kotlin写接口, 发现SpringBoot的注解来配置DI容器的功能非常的好用: 找了一下发现没有一个net的框架实现了,所以我决定自己写一个!

    这个是我基于autofac框架的一个扩展组件,实现了以下功能:

    • Component标签:注册到DI容器直接打上一个即可
    • Configuration注解和Bean标签:实现了用实例方法注册到DI容器
    • PropertySource和Value标签:实现了注入配置文件属性的值到DI容器
    • Autowired标签:实现了自动装配

    玩过java的spring框架就应该看这个标签名称很熟悉,因为名称是一模一样的。 功能也是高度保持一致

    var builder = new ContainerBuilder();
    
    // 注册autofac打标签模式
    builder.RegisterModule(new AutofacAnnotationModule(typeof(AnotationTest).Assembly));
    //如果需要开启支持循环注入
    //builder.RegisterModule(new AutofacAnnotationModule(typeof(AnotationTest).Assembly).SetAllowCircularDependencies(true));
    var container = builder.Build();
    var serviceB = container.Resolve<B>();
    
    

    AutofacAnnotationModule有两种构造方法

    1. 可以传一个Assebly列表 (这种方式会注册传入的Assebly里面打了标签的类)
    2. 可以传一个AsseblyName列表 (这种方式是先会根据AsseblyName查找Assebly 然后在注册)

    Component标签

    说明:只能打在class上面(且不能是抽象class) 把某个类注册到autofac容器 例如:

    1. 无构造方法的方式 等同于 builder.RegisterType();
    //class A 注册到容器
    [Component]
    public class A
    {
    	public string Name { get; set; }
    }
    //如果 A有父类或者实现了接口 也会自动注册(排除非public的因为autofac不能注册私有类或接口)
    public interface IB
    {
    
    }	
    public class ParentB:IB
    {
    	public string Name1 { get; set; }
    }
    
    //class B 注册到容器 并且把 B作为ParentB注册到容器 并且把B最为IB注册到容器
    [Component]
    public class B:ParentB
    {
    	public string Name { get; set; }
    }	
    
    1. 指定Scope [需要指定AutofacScope属性 如果不指定为则默认为AutofacScope.InstancePerDependency]
        [Component(AutofacScope = AutofacScope.SingleInstance)]
        public class A
        {
            public string Name { get; set; }
        }
    
    1. 指定类型注册 等同于 builder.RegisterType<A6>().As()
        public class B
        {
    
        }
    	
        [Component(typeof(B))]
        public class A6:B
        {
    
        }
    
    1. 指定名字注册 等同于 builder.RegisterType<A6>().Keyed<A4>("a4")
        [Component("a4")]
        public class A4
        {
            public string School { get; set; } = "测试2";
        }
    
    1. 其他属性说明
    • OrderIndex 注册顺序 【顺序值越大越早注册到容器,但是一个类型多次注册那么装配的时候会拿OrderIndex最小的值(因为autofac的规则会覆盖)】
    • InjectProperties 是否默认装配属性 【默认为true】
        [Component(InitMethod = "start",DestroyMetnod = "destroy")]
        public class A30
        {
            [Value("aaaaa")]
            public string Test { get; set; }
    
            public A29 a29;
    
            void start(IComponentContext context)
            {
                this.Test = "bbbb";
                a29 = context.Resolve<A29>();
            }
    
            void destroy()
            {
                this.Test = null;
                a29.Test = null;
            }
        }
    	
    
        public class B
        {
    
        }
    	
        [Component(typeof(B),"a5")]
        public class A5:B
        {
            public string School { get; set; } = "测试a5";
            public override string GetSchool()
            {
                return this.School;
            }
        }
    

    Autowired 自动装配

    可以打在Field Property 构造方法的Parameter上面 其中Field 和 Property 支持在父类

        [Component]
        public class A16
        {
    	public A16([Autowired]A21 a21)
            {
                Name = name;
                A21 = a21;
            }
    		
            [Autowired("A13")]
            public B b1;
    
    
            [Autowired]
            public B B { get; set; }
    		
    	//Required默认为true 如果装载错误会抛异常出来。如果指定为false则不抛异常
    	[Autowired("adadada",Required = false)]
            public B b1;
        }
    

    Value 和 PropertySource

    • PropertySource类似Spring里面的PropertySource 可以指定数据源 支持 xml json格式 支持内嵌资源
    1. json格式的文件
    {
      "a10": "aaaaaaaaa1",
      "list": [ 1, 2, 3 ],
      "dic": {
        "name": "name1"
      },
      "testInitField": 1,
      "testInitProperty": 1,
    }
    
        [Component]
        [PropertySource("/file/appsettings1.json")]
        public class A10
        {
            public A10([Value("#{a10}")]string school,[Value("#{list}")]List<int> list,[Value("#{dic}")]Dictionary<string,string> dic)
            {
                this.School = school;
                this.list = list;
                this.dic = dic;
    
            }
            public string School { get; set; }
            public List<int> list { get; set; } 
            public Dictionary<string,string> dic { get; set; } 
    		
    	[Value("#{testInitField}")]
            public int test;
    		
    	[Value("#{testInitProperty}")]
            public int test2 { get; set; }
    		
    	//可以直接指定值
    	[Value("2")]
    	public int test3 { get; set; }
        }
    
    1. xml格式的文件
    <?xml version="1.0" encoding="utf-8" ?>
    <autofac>
      <a11>aaaaaaaaa1</a11>
      <list name="0">1</list>
      <list name="1">2</list>
      <list name="2">3</list>
      <dic name="name">name1</dic>
    </autofac>
    
    
        [Component]
        [PropertySource("/file/appsettings1.xml")]
        public class A11
        {
            public A11([Value("#{a11}")]string school,[Value("#{list}")]List<int> list,[Value("#{dic}")]Dictionary<string,string> dic)
            {
                this.School = school;
                this.list = list;
                this.dic = dic;
    
            }
            public string School { get; set; }
            public List<int> list { get; set; } 
            public Dictionary<string,string> dic { get; set; } 
        }
    
    1. 不指定PropertySource的话会默认从工程目录的 appsettings.json获取值

    AutoConfiguration标签 和 Bean标签

        [AutoConfiguration]
        public class TestConfiguration
        {
            //Bean标签只能搭配AutoConfiguration标签使用,在其他地方没有效
    	//并且是单例注册
            [Bean]
            private ITestModel4 getTest5()
            {
                return new TestModel4
                {
                    Name = "getTest5"
                };
            }
        }
    

    在容器build完成后执行: 扫描指定的程序集,发现如果有打了AutoConfiguration标签的class,就会去识别有Bean标签的方法,并执行方法将方法返回实例注册为方法返回类型到容器! 一个程序集可以有多个AutoConfiguration标签的class会每个都加载。

    AutoConfiguration标签的其他属性:

    • OrderIndex 可以通过OrderIndex设置优先级,越大的越先加载。
    • Key 也可以通过Key属性设置

    搭配如下代码可以设置过滤你想要加载的,比如你想要加载Key = “test” 的所有 AutoConfiguration标签class //builder.RegisterModule(new AutofacAnnotationModule(typeof(AnotationTest).Assembly).SetAutofacConfigurationKey("test"));

    Bean标签的其他属性:

    • Key 也可以通过Key属性设置 比如有多个方法返回的类型相同 可以设置Key来区分

    AutofacAnnotation标签模式和autofac写代码性能测试对比

        public class AutofacAutowiredResolveBenchmark
        {
            private IContainer _container;
    
            [GlobalSetup]
            public void Setup()
            {
                var builder = new ContainerBuilder();
                builder.RegisterType<A13>().As<B>().WithAttributeFiltering();
                builder.RegisterType<Log>().As<AsyncInterceptor>();
                builder.RegisterType<Log2>().Keyed<AsyncInterceptor>("log2");
                builder.RegisterType<A21>().WithAttributeFiltering().PropertiesAutowired();
                builder.RegisterType<A23>().As<IA23>().WithAttributeFiltering().PropertiesAutowired().EnableInterfaceInterceptors()
                    .InterceptedBy(typeof(AsyncInterceptor));
                builder.RegisterType<A25>().WithAttributeFiltering().PropertiesAutowired().EnableClassInterceptors()
                    .InterceptedBy(new KeyedService("log2", typeof(AsyncInterceptor)));
                _container = builder.Build();
            }
    
            [Benchmark]
            public void Autofac()
            {
                var a1 = _container.Resolve<A25>();
                var a2= a1.A23.GetSchool();
            }
        }
    
    
    BenchmarkDotNet=v0.11.3, OS=Windows 10.0.18362
    Intel Core i7-7700K CPU 4.20GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores
    .NET Core SDK=2.2.300
      [Host]     : .NET Core 2.1.13 (CoreCLR 4.6.28008.01, CoreFX 4.6.28008.01), 64bit RyuJIT  [AttachedDebugger]
      DefaultJob : .NET Core 2.1.13 (CoreCLR 4.6.28008.01, CoreFX 4.6.28008.01), 64bit RyuJIT
    
    
    
    MethodMeanErrorStdDev
    Autofac 30.30 us 0.2253 us 0.1997 us
       //打标签模式
       public class AutowiredResolveBenchmark
        {
            private IContainer _container;
            
            [GlobalSetup]
            public void Setup()
            {
                var builder = new ContainerBuilder();
                builder.RegisterModule(new AutofacAnnotationModule(typeof(A13).Assembly));
                _container = builder.Build();
            }
            
            [Benchmark]
            public void AutofacAnnotation()
            {
                var a1 = _container.Resolve<A25>();
                var a2= a1.A23.GetSchool();
            }
        }
    
    
    BenchmarkDotNet=v0.11.3, OS=Windows 10.0.18362
    Intel Core i7-7700K CPU 4.20GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores
    .NET Core SDK=2.2.300
      [Host]     : .NET Core 2.1.13 (CoreCLR 4.6.28008.01, CoreFX 4.6.28008.01), 64bit RyuJIT  [AttachedDebugger]
      DefaultJob : .NET Core 2.1.13 (CoreCLR 4.6.28008.01, CoreFX 4.6.28008.01), 64bit RyuJIT
    
    
    
    MethodMeanErrorStdDev
    AutofacAnnotation 35.36 us 0.1504 us 0.1407 us
  • 相关阅读:
    Linq增删查改
    ObjectiveC 的一些记录
    MAX+VC版的RenderMonkey
    PHP校验身份证是否合法
    将小程序scene中的字符串转为对象
    使用JavaScript与Servlet实现客户端与服务器端验证
    分析jdbc程序的编写步骤和原理
    解析Tomcat生成源代码分析javaBean与对象的生成关系
    《Python基础教程》要点(十):充电时刻:导入模块
    《Python基础教程》要点(七):更加抽象:类
  • 原文地址:https://www.cnblogs.com/yudongdong/p/11577975.html
Copyright © 2020-2023  润新知