C# Spring.Net IOC Autufac学习笔记

一、为什么使用Autofac?

Autofac是.NET领域最为流行的IoC框架之一,传说是速度最快的一个。

1.1、性能

有人专门做了测试:

在这里插入图片描述

1.2、优点

1)与C#语言联系很紧密。C#里的很多编程方式都可以为Autofac使用,例如可以使用Lambda表达式注册组件。

2)较低的学习曲线。学习它非常的简单,只要你理解了IoC和DI的概念以及在何时需要使用它们。

3)支持JSON/XML配置。

4)自动装配。

5)与Asp.Net MVC集成。

6)微软的Orchad开源程序使用的就是Autofac,可以看出它的方便和强大。

1.3、资源

官方网站:http://autofac.org/

GitHub网址:https://github.com/autofac/Autofac

学习资料:Autofac中文文档[link](https://autofaccn.readthedocs.io/zh/latest/index.html/).

二、数据准备

2.1、新建项目

在这里插入图片描述

IService下的接口类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LinkTo.Test.Autofac.IService
{
    /// <summary>
    /// 动物吠声接口类
    /// </summary>
    public interface IAnimalBark
    {
        /// <summary>
        /// 吠叫
        /// </summary>
        void Bark();
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LinkTo.Test.Autofac.IService
{
    /// <summary>
    /// 动物睡眠接口类
    /// </summary>
    public interface IAnimalSleep
    {
        /// <summary>
        /// 睡眠
        /// </summary>
        void Sleep();
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LinkTo.Test.Autofac.IService
{
    /// <summary>
    /// 学校接口类
    /// </summary>
    public interface ISchool
    {
        /// <summary>
        /// 放学
        /// </summary>
        void LeaveSchool();
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LinkTo.Test.Autofac.IService
{
    /// <summary>
    /// 学生接口类
    /// </summary>
    public interface IStudent
    {
        /// <summary>
        /// 增加学生
        /// </summary>
        /// <param name="studentID">学生ID</param>
        /// <param name="studentName">学生姓名</param>
        void Add(string studentID, string studentName);
    }
}
Service下的接口实现类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LinkTo.Test.Autofac.IService;

namespace LinkTo.Test.Autofac.Service
{
    /// <summary>
    /// 猫类
    /// </summary>
    public class Cat : IAnimalSleep
    {
        /// <summary>
        /// 睡眠
        /// </summary>
        public void Sleep()
        {
            Console.WriteLine("小猫咪睡着了zZ");
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LinkTo.Test.Autofac.IService;

namespace LinkTo.Test.Autofac.Service
{
    /// <summary>
    /// 狗类
    /// </summary>
    public class Dog : IAnimalBark, IAnimalSleep
    {
        /// <summary>
        /// 吠叫
        /// </summary>
        public void Bark()
        {
            Console.WriteLine("汪汪汪");
        }

        /// <summary>
        /// 睡眠
        /// </summary>
        public void Sleep()
        {
            Console.WriteLine("小狗狗睡着了zZ");
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LinkTo.Test.Autofac.IService;

namespace LinkTo.Test.Autofac.Service
{
    /// <summary>
    /// 学校类
    /// </summary>
    public class School : ISchool
    {
        /// <summary>
        /// IAnimalBark属性
        /// </summary>
        public IAnimalBark AnimalBark { get; set; }

        /// <summary>
        /// 放学
        /// </summary>
        public void LeaveSchool()
        {
            AnimalBark.Bark();
            Console.WriteLine("你家的熊孩子放学了⊙o⊙");
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LinkTo.Test.Autofac.IService;

namespace LinkTo.Test.Autofac.Service
{
    /// <summary>
    /// 学生类
    /// </summary>
    public class Student : IStudent
    {
        /// <summary>
        /// 无参构造函数
        /// </summary>
        public Student()
        { }

        /// <summary>
        /// 有参构造函数
        /// </summary>
        /// <param name="studentID">学生ID</param>
        /// <param name="studentName">学生姓名</param>
        public Student(string studentID, string studentName)
        {
            Add(studentID, studentName);
        }

        /// <summary>
        /// 增加学生
        /// </summary>
        /// <param name="studentID">学生ID</param>
        /// <param name="studentName">学生姓名</param>
        public void Add(string studentID, string studentName)
        {
            Console.WriteLine($"新增的学生是:{studentName}");
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using LinkTo.Test.Autofac.IService;

namespace LinkTo.Test.Autofac.Service
{
    /// <summary>
    /// 动物摇尾巴
    /// </summary>
    public class AnimalWagging
    {
        /// <summary>
        /// IAnimalBark属性
        /// </summary>
        IAnimalBark animalBark;

        /// <summary>
        /// 有参构造函数
        /// </summary>
        /// <param name="bark">IAnimalBark变量</param>
        public AnimalWagging(IAnimalBark bark)
        {
            animalBark = bark;
        }

        /// <summary>
        /// 摇尾巴
        /// </summary>
        public virtual void Wagging()
        {
            animalBark.Bark();
            Console.WriteLine("摇尾巴");
        }

        /// <summary>
        /// 计数
        /// </summary>
        /// <returns></returns>
        public static int Count()
        {
            return 6;
        }

        /// <summary>
        /// 任务
        /// </summary>
        /// <param name="name">动物名称</param>
        /// <returns></returns>
        public virtual async Task<string> WaggingAsync(string name)
        {
            var result = await Task.Run(() => Count());
            return $"{name}摇了{result}下尾巴";
        }
    }
}

2.2、Autofac安装

Client项目右键->管理 NuGet 程序包->Autofac。

在这里插入图片描述

三、IoC-注册

3.1、类型注册

a)类型注册:使用RegisterType进行注册。
//注册Autofac组件
ContainerBuilder builder = new ContainerBuilder();
//注册实现类Student,当我们请求IStudent接口的时候,返回的是类Student的对象。
builder.RegisterType<Student>().As<IStudent>();
//上面这句也可改成下面这句,这样请求Student实现了的任何接口的时候,都会返回Student对象。
//builder.RegisterType<Student>().AsImplementedInterfaces();
IContainer container = builder.Build();
//请求IStudent接口
IStudent student = container.Resolve<IStudent>();
student.Add("1001", "Hello");
b)类型注册(别名):假如一个接口有多个实现类,可以在注册时起别名。
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<Dog>().Named<IAnimalSleep>("Dog");
builder.RegisterType<Cat>().Named<IAnimalSleep>("Cat");
IContainer container = builder.Build();

var dog = container.ResolveNamed<IAnimalSleep>("Dog");
dog.Sleep();
var cat = container.ResolveNamed<IAnimalSleep>("Cat");
cat.Sleep();
c)类型注册(枚举):假如一个接口有多个实现类,也可以使用枚举的方式注册。
public enum AnimalType
{
    Dog,
    Cat
}
            ContainerBuilder builder = new ContainerBuilder();
            builder.RegisterType<Dog>().Keyed<IAnimalSleep>(AnimalType.Dog);
            builder.RegisterType<Cat>().Keyed<IAnimalSleep>(AnimalType.Cat);
            IContainer container = builder.Build();

            var dog = container.ResolveKeyed<IAnimalSleep>(AnimalType.Dog);
            dog.Sleep();
            var cat = container.ResolveKeyed<IAnimalSleep>(AnimalType.Cat);
            cat.Sleep();

3.2、实例

注册

 		ContainerBuilder builder = new ContainerBuilder();
        builder.RegisterInstance<IStudent>(new Student());
        IContainer container = builder.Build();

        IStudent student = container.Resolve<IStudent>();
        student.Add("1001", "Hello");

3.3、Lambda注册

a)Lambda注册

  	ContainerBuilder builder = new ContainerBuilder();
    builder.Register(c => new Student()).As<IStudent>();
    IContainer container = builder.Build();

    IStudent student = container.Resolve<IStudent>();
    student.Add("1001", "Hello");

b)Lambda注册(NamedParameter)

ContainerBuilder builder = new ContainerBuilder();
        builder.Register<IAnimalSleep>((c, p) =>
            {
                var type = p.Named<string>("type");
                if (type == "Dog")
                {
                    return new Dog();
                }
                else
                {
                    return new Cat();
                }
            }).As<IAnimalSleep>();
        IContainer container = builder.Build();

        var dog = container.Resolve<IAnimalSleep>(new NamedParameter("type", "Dog"));
        dog.Sleep();

3.4、程序集注册

如果有很多接口及实现类,假如觉得这种一一注册很麻烦的话,可以一次性全部注册,当然也可以加筛选条件。

ContainerBuilder builder = new ContainerBuilder();
        Assembly assembly = Assembly.Load("LinkTo.Test.Autofac.Service");   //实现类所在的程序集名称
        builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces();  //常用
        //builder.RegisterAssemblyTypes(assembly).Where(t=>t.Name.StartsWith("S")).AsImplementedInterfaces();  //带筛选
        //builder.RegisterAssemblyTypes(assembly).Except<School>().AsImplementedInterfaces();  //带筛选
        IContainer container = builder.Build();

        //单实现类的用法
        IStudent student = container.Resolve<IStudent>();
        student.Add("1001", "Hello");

        //多实现类的用法
        IEnumerable<IAnimalSleep> animals = container.Resolve<IEnumerable<IAnimalSleep>>();
        foreach (var item in animals)
        {
            item.Sleep();
        }

3.5、泛型注册

 		ContainerBuilder builder = new ContainerBuilder();
        builder.RegisterGeneric(typeof(List<>)).As(typeof(IList<>));
        IContainer container = builder.Build();

        IList<string> list = container.Resolve<IList<string>>();

3.6、默认注册

ContainerBuilder builder = new ContainerBuilder();
        //对于同一个接口,后面注册的实现会覆盖之前的实现。
        //如果不想覆盖的话,可以用PreserveExistingDefaults,这样会保留原来注册的实现。
        builder.RegisterType<Dog>().As<IAnimalSleep>();
        builder.RegisterType<Cat>().As<IAnimalSleep>().PreserveExistingDefaults();  //指定为非默认值
        IContainer container = builder.Build();

        var dog = container.Resolve<IAnimalSleep>();
        dog.Sleep();

四、IoC-注入

4.1、构造函数注入

ContainerBuilder builder = new ContainerBuilder();
        builder.RegisterType<AnimalWagging>();
        builder.RegisterType<Dog>().As<IAnimalBark>();
        IContainer container = builder.Build();

        AnimalWagging animal = container.Resolve<AnimalWagging>();
        animal.Wagging();

4.2、属性注入

 ContainerBuilder builder = new ContainerBuilder();
        Assembly assembly = Assembly.Load("LinkTo.Test.Autofac.Service");                           //实现类所在的程序集名称
        builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces().PropertiesAutowired();    //常用
        IContainer container = builder.Build();

        ISchool school = container.Resolve<ISchool>();
        school.LeaveSchool();

五、IoC-事件

Autofac在组件生命周期的不同阶段,共对应了5个事件,执行顺序如下所示:

1.OnRegistered->2.OnPreparing->3.OnActivating->4.OnActivated->5.OnRelease
ContainerBuilder builder = new ContainerBuilder();
        builder.RegisterType<Student>().As<IStudent>()
            .OnRegistered(e => Console.WriteLine("OnRegistered:在注册的时候调用"))
            .OnPreparing(e => Console.WriteLine("OnPreparing:在准备创建的时候调用"))
            .OnActivating(e => Console.WriteLine("OnActivating:在创建之前调用"))
            //.OnActivating(e => e.ReplaceInstance(new Student("1000", "Test")))
            .OnActivated(e => Console.WriteLine("OnActivated:在创建之后调用"))
            .OnRelease(e => Console.WriteLine("OnRelease:在释放占用的资源之前调用"));
        using (IContainer container = builder.Build())
        {
            IStudent student = container.Resolve<IStudent>();
            student.Add("1001", "Hello");
        }

六、IoC-生命周期

6.1、Per Dependency

Per Dependency:为默认的生命周期,也被称为"transient"或"factory",其实就是每次请求都创建一个新的对象。

ContainerBuilder builder = new ContainerBuilder();
Assembly assembly = Assembly.Load("LinkTo.Test.Autofac.Service");                                                   //实现类所在的程序集名称
builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces().PropertiesAutowired().InstancePerDependency();    //常用
IContainer container = builder.Build();

ISchool school1 = container.Resolve<ISchool>();
ISchool school2 = container.Resolve<ISchool>();
Console.WriteLine(school1.Equals(school2));

6.2、Single Instance

Single Instance:就是每次都用同一个对象。
ContainerBuilder builder = new ContainerBuilder();
        Assembly assembly = Assembly.Load("LinkTo.Test.Autofac.Service");                                           //实现类所在的程序集名称
        builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces().PropertiesAutowired().SingleInstance();   //常用
        IContainer container = builder.Build();

        ISchool school1 = container.Resolve<ISchool>();
        ISchool school2 = container.Resolve<ISchool>();
        Console.WriteLine(ReferenceEquals(school1, school2));

6.3、Per Lifetime Scope

Per Lifetime Scope:同一个Lifetime生成的对象是同一个实例。
ContainerBuilder builder = new ContainerBuilder();
        builder.RegisterType<School>().As<ISchool>().InstancePerLifetimeScope();
        IContainer container = builder.Build();
        ISchool school1 = container.Resolve<ISchool>();
        ISchool school2 = container.Resolve<ISchool>();
        Console.WriteLine(school1.Equals(school2));
        using (ILifetimeScope lifetime = container.BeginLifetimeScope())
        {
            ISchool school3 = lifetime.Resolve<ISchool>();
            ISchool school4 = lifetime.Resolve<ISchool>();
            Console.WriteLine(school3.Equals(school4));
            Console.WriteLine(school2.Equals(school3));
        }

七、IoC-通过配置文件使用Autofac

7.1、组件安装

Client项目右键->管理 NuGet 程序包->Autofac.Configuration及Microsoft.Extensions.Configuration.Xml。

在这里插入图片描述
在这里插入图片描述

7.2、配置文件

新建一个AutofacConfigIoC.xml文件,在其属性的复制到输出目录项下选择始终复制。
<?xml version="1.0" encoding="utf-8" ?>
<autofac defaultAssembly="LinkTo.Test.Autofac.IService">
  <!--无注入-->
  <components name="1001">
    <type>LinkTo.Test.Autofac.Service.Student, LinkTo.Test.Autofac.Service</type>
    <services name="0" type="LinkTo.Test.Autofac.IService.IStudent" />
    <injectProperties>true</injectProperties>
  </components>
  <components name="1002">
    <type>LinkTo.Test.Autofac.Service.Dog, LinkTo.Test.Autofac.Service</type>
    <services name="0" type="LinkTo.Test.Autofac.IService.IAnimalBark" />
    <injectProperties>true</injectProperties>
  </components>
  <!--构造函数注入-->
  <components name="2001">
    <type>LinkTo.Test.Autofac.Service.AnimalWagging, LinkTo.Test.Autofac.Service</type>
    <services name="0" type="LinkTo.Test.Autofac.Service.AnimalWagging, LinkTo.Test.Autofac.Service" />
    <injectProperties>true</injectProperties>
  </components>
  <!--属性注入-->
  <components name="3001">
    <type>LinkTo.Test.Autofac.Service.School, LinkTo.Test.Autofac.Service</type>
    <services name="0" type="LinkTo.Test.Autofac.IService.ISchool" />
    <injectProperties>true</injectProperties>
  </components>
</autofac>

7.3、测试代码

 //加载配置
    ContainerBuilder builder = new ContainerBuilder();
    var config = new ConfigurationBuilder();
    config.AddXmlFile("AutofacConfigIoC.xml");
    var module = new ConfigurationModule(config.Build());
    builder.RegisterModule(module);
    IContainer container = builder.Build();
    //无注入测试
    IStudent student = container.Resolve<IStudent>();
    student.Add("1002", "World");
    //构造函数注入测试
    AnimalWagging animal = container.Resolve<AnimalWagging>();
    animal.Wagging();
    //属性注入测试
    ISchool school = container.Resolve<ISchool>();
    school.LeaveSchool();

八、AOP

8.1、组件安装

Client项目右键->管理 NuGet 程序包->Autofac.Extras.DynamicProxy。

在这里插入图片描述

8.2、拉截器

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Castle.DynamicProxy;

namespace LinkTo.Test.Autofac.Client
{
    /// <summary>
    /// 拦截器:需实现IInterceptor接口。
    /// </summary>
    public class CallLogger : IInterceptor
    {
        private readonly TextWriter _output;

        public CallLogger(TextWriter output)
        {
            _output = output;
        }

        /// <summary>
        /// 拦截方法:打印被拦截的方法--执行前的名称、参数以及执行后的返回结果。
        /// </summary>
        /// <param name="invocation">被拦截方法的信息</param>
        public void Intercept(IInvocation invocation)
        {
            //空白行
            _output.WriteLine();

            //在下一个拦截器或目标方法处理之前的处理
            _output.WriteLine($"调用方法:{invocation.Method.Name}");

            if (invocation.Arguments.Length > 0)
            {
                _output.WriteLine($"参数:{string.Join(", ", invocation.Arguments.Select(a => (a ?? "").ToString()).ToArray())}");
            }

            //调用下一个拦截器(若存在),直到最终的目标方法(Target Method)。
            invocation.Proceed();

            //获取被代理方法的返回类型
            var returnType = invocation.Method.ReturnType;

            //异步方法
            if (IsAsyncMethod(invocation.Method))
            {
                //Task:返回值是固定类型
                if (returnType != null && returnType == typeof(Task))
                {
                    //定义一个异步方法来等待目标方法返回的Task
                    async Task Continuation() => await (Task)invocation.ReturnValue;
                    //Continuation()中并没有使用await,所以Continuation()就如同步方法一样是阻塞的。
                    invocation.ReturnValue = Continuation();
                }
                //Task<T>:返回值是泛型类型
                else
                {
                    //获取被代理方法的返回类型
                    var returnTypeT = invocation.Method.ReflectedType;
                    if (returnTypeT != null)
                    {
                        //获取泛型参数集合,集合中的第一个元素等价于typeof(Class)。
                        var resultType = invocation.Method.ReturnType.GetGenericArguments()[0];
                        //利用反射获得等待返回值的异步方法
                        MethodInfo methodInfo = typeof(CallLogger).GetMethod("HandleAsync", BindingFlags.Public | BindingFlags.Instance);
                        //调用methodInfo类的MakeGenericMethod()方法,用获得的类型T(<resultType>)来重新构造HandleAsync()方法。
                        var mi = methodInfo.MakeGenericMethod(resultType);
                        //Invoke:使用指定参数调用由当前实例表示的方法或构造函数。
                        invocation.ReturnValue = mi.Invoke(this, new[] { invocation.ReturnValue });
                    }
                }

                var type = invocation.Method.ReturnType;
                var resultProperty = type.GetProperty("Result");

                if (resultProperty != null)
                    _output.WriteLine($"方法结果:{resultProperty.GetValue(invocation.ReturnValue)}");
            }
            //同步方法
            else
            {
                if (returnType != null && returnType != typeof(void))
                    _output.WriteLine($"方法结果:{invocation.ReturnValue}");
            }
        }

        /// <summary>
        /// 判断是否异步方法
        /// </summary>
        public static bool IsAsyncMethod(MethodInfo method)
        {
            return 
                (
                    method.ReturnType == typeof(Task) || 
                    (method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))
                );
        }

        /// <summary>
        /// 构造等待返回值的异步方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="task"></param>
        /// <returns></returns>
        public async Task<T> HandleAsync<T>(Task<T> task)
        {
            var t = await task;
            return t;
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Castle.DynamicProxy;

namespace LinkTo.Test.Autofac.Client
{
    public class CallTester: IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            Console.WriteLine("啥也不干");
            invocation.Proceed();
            Console.WriteLine("也不干啥");
        }
    }
}

8.3、测试代码

注意:对于以类方式的注入,Autofac Interceptor要求类的方法必须为virtual方法。如AnimalWagging类的Wagging()、WaggingAsync(string name)都加了virtual修饰符。

ContainerBuilder builder = new ContainerBuilder();

        //注册拦截器
        builder.Register(c => new CallLogger(Console.Out));
        builder.Register(c => new CallTester());

        //动态注入拦截器

        //这里定义了两个拦截器,注意它们的顺序。
        builder.RegisterType<Student>().As<IStudent>().InterceptedBy(typeof(CallLogger), typeof(CallTester)).EnableInterfaceInterceptors();

        //这里定义了一个拦截器
        builder.RegisterType<AnimalWagging>().InterceptedBy(typeof(CallLogger)).EnableClassInterceptors();
        builder.RegisterType<Dog>().As<IAnimalBark>();

        IContainer container = builder.Build();
        IStudent student = container.Resolve<IStudent>();
        student.Add("1003", "Kobe");

        AnimalWagging animal = container.Resolve<AnimalWagging>();
        animal.Wagging();

        Task<string> task = animal.WaggingAsync("哈士奇");
        Console.WriteLine($"{task.Result}");
IoC参考自:

https://www.xin3721.com/ArticlecSharp/c14013.html

https://www.cnblogs.com/GoogleGetZ/p/10218721.html

http://niuyi.github.io/blog/2012/04/06/autofac-by-unit-test/

https://www.cnblogs.com/kissdodog/p/3611799.html



AOP参考自:

https://www.cnblogs.com/stulzq/p/6880394.html

https://blog.csdn.net/weixin_38211198/article/details/105925821

https://blog.csdn.net/q932104843/article/details/97611912

转载自:https://www.cnblogs.com/atomy/p/12834804.html

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值