C#使用Autofac实现控制反转IoC和面向切面编程AOP
Autofac是一个.net下非常优秀,性能非常好的IOC容器(.net下效率最高的容器),加上AOP简直是如虎添翼。Autofac的AOP是通过Castle(也是一个容器)项目的核心部分实现的,名为Autofac.Extras.DynamicProxy,顾名思义,其实现方式为动态代理。
使用方式比较简单,先新建一个控制台项目,然后在Nuget上搜索Autofac.Aop并安装,如下顺序:
或者通过命令安装:
Install-Package Autofac.Aop
安装成功之后会项目会增加几个个引用,如下图:
1. 创建拦截器
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; //先在Nuget上搜索Autofac.Aop安装 using Castle.DynamicProxy; namespace AutofacDEMO { /// <summary> /// 拦截器 需要实现 IInterceptor接口 Intercept方法 /// </summary> public class LogInterceptor : IInterceptor { /// <summary> /// 拦截方法 打印被拦截的方法执行前的名称、参数和方法执行后的 返回结果 /// </summary> /// <param name="invocation">包含被拦截方法的信息</param> public void Intercept(IInvocation invocation) { Console.WriteLine("方法执行前:拦截{0}类下的方法{1}的参数是{2}", invocation.InvocationTarget.GetType(), invocation.Method.Name, string.Join(", ", invocation.Arguments.Select(a => (a ?? "").ToString()).ToArray())); //在被拦截的方法执行完毕后 继续执行 invocation.Proceed(); Console.WriteLine("方法执行完毕,返回结果:{0}", invocation.ReturnValue); Console.WriteLine(); } } }
2. 创建拦截容器
var builder = new ContainerBuilder();
3. 注册拦截器到Autofac容器
拦截器必须注册到Aufofac容器中,可以通过拦截器类型或者命名注入,这两种方式会让使用拦截器的方法有所不同
// 命名注入 builder.Register(c => new LogInterceptor()).Named<IInterceptor>("log-calls"); //类型注入 builder.Register(c => new LogInterceptor());
//或者 builder.RegisterType<LogInterceptor>();
4. 启用拦截器
启用拦截器主要有两个方法:EnableInterfaceInterceptors(),EnableClassInterceptors()。
EnableInterfaceInterceptors方法会动态创建一个接口代理
EnableClassInterceptors方法会创建一个目标类的子类代理类,这里需要注意的是只会拦截虚方法,重写方法
注意:需要引用Autofac.Extras.DynamicProxy2才能使用上面两个方法
//启用类代理拦截 //方式一:给类型上加特性Attribute builder.RegisterType<Student>().EnableClassInterceptors(); //方式二:在注册类型到容器的时候动态注入拦截器(去掉类型上的特性Attribute) builder.RegisterType<Teacher>().InterceptedBy(typeof(LogInterceptor)).EnableClassInterceptors(); //启用接口代理拦截 //方式一:给类型上加特性Attribute builder.RegisterType<Man>().As<IPerson>().EnableInterfaceInterceptors(); //方式二:在注册类型到容器的时候动态注入拦截器(去掉类型上的特性Attribute) builder.RegisterType<Man>().As<IPerson>().InterceptedBy(typeof(LogInterceptor)).EnableInterfaceInterceptors();
5. 指明要拦截的类型
有两种方法:
第一种:给类型加上特性Attribute
第二种:在注册类型到容器的时候动态注入拦截器
//动态注入拦截器 builder.RegisterType<Student>().InterceptedBy(typeof(LogInterceptor)).EnableClassInterceptors();
6. 测试效果如下
第一种:类代理拦截
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Autofac.Extras.DynamicProxy2; namespace AutofacDEMO { /// <summary> /// 继承接口,并实现方法,给类型加上特性Attribute /// </summary> [Intercept(typeof(LogInterceptor))] public class Student { public string Name; public Teacher Teacher; public Subject Subject; /// <summary> /// 必须是虚方法 /// </summary> public virtual void Say() { Console.WriteLine("你正在调用Say方法!学生姓名:" + Name); } } [Intercept(typeof(LogInterceptor))] public class Teacher { /// <summary> /// 必须是虚方法 /// </summary> public virtual void Show() { Console.WriteLine("I am Teacher's class !"); } } public class Subject { /// <summary> /// 必须是虚方法 /// </summary> public virtual void Show() { Console.WriteLine("I am Subject's class !" ); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Autofac; using Autofac.Extras.DynamicProxy2; namespace AutofacDEMO { class Program { static void Main(string[] args) { //启用拦截器主要有两个方法:EnableInterfaceInterceptors(),EnableClassInterceptors() //EnableInterfaceInterceptors方法会动态创建一个接口代理 //EnableClassInterceptors方法会创建一个目标类的子类代理类,这里需要注意的是只会拦截虚方法,重写方法 //注意:需要引用Autofac.Extras.DynamicProxy2才能使用上面两个方法 #region 启用类代理拦截 //创建拦截容器 var builder = new ContainerBuilder(); //注册拦截器到容器 builder.RegisterType<LogInterceptor>(); //方式一:给类型上加特性Attribute builder.RegisterType<Student>().EnableClassInterceptors(); builder.RegisterType<Teacher>().EnableClassInterceptors(); //方式二:在注册类型到容器的时候动态注入拦截器(去掉类型上的特性Attribute) //builder.RegisterType<Teacher>().InterceptedBy(typeof(LogInterceptor)).EnableClassInterceptors(); //builder.RegisterType<Student>().InterceptedBy(typeof(LogInterceptor)).EnableClassInterceptors(); //属性注入 builder.Register(c => new Student { Teacher = c.Resolve<Teacher>(), Subject = new Subject(), Name = "张三" }); using (var container = builder.Build()) { //从容器获取对象 var Student = container.Resolve<Student>(); Student.Say(); Student.Subject.Show(); Student.Teacher.Show(); } Console.ReadLine(); #endregion } } }
第二种:接口代理拦截
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace AutofacDEMO { /// <summary> /// 定义一个接口 /// </summary> public interface IPerson { void Say(string Name); } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Autofac.Extras.DynamicProxy2; namespace AutofacDEMO { /// <summary> /// 继承接口,并实现方法,给类型加上特性Attribute /// </summary> [Intercept(typeof(LogInterceptor))] public class Man: IPerson { public string Age; public void Say(string Name) { Console.WriteLine("男人调用Say方法!姓名:" + Name + ",年龄:" + Age); } } /// <summary> /// 继承接口,并实现方法,给类型加上特性Attribute /// </summary> [Intercept(typeof(LogInterceptor))] public class Woman : IPerson { public void Say(string Name) { Console.WriteLine("女人调用Say方法!姓名:" + Name); } } /// <summary> /// 管理类 /// </summary> public class PersonManager { IPerson _Person; /// <summary> /// 根据传入的类型动态创建对象 /// </summary> /// <param name="ds"></param> public PersonManager(IPerson Person) { _Person = Person; } public void Say(string Name) { _Person.Say(Name); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Autofac; using Autofac.Extras.DynamicProxy2; namespace AutofacDEMO { class Program { static void Main(string[] args) { //启用拦截器主要有两个方法:EnableInterfaceInterceptors(),EnableClassInterceptors() //EnableInterfaceInterceptors方法会动态创建一个接口代理 //EnableClassInterceptors方法会创建一个目标类的子类代理类,这里需要注意的是只会拦截虚方法,重写方法 //注意:需要引用Autofac.Extras.DynamicProxy2才能使用上面两个方法 #region 启用接口代理拦截(推荐用这种方式) //创建拦截容器 var builder2 = new ContainerBuilder(); //注册拦截器到容器 builder2.RegisterType<LogInterceptor>(); //构造函数注入(只要调用者传入实现该接口的对象,就实现了对象创建,下面两种方式) builder2.RegisterType<PersonManager>(); //方式一:给类型上加特性Attribute //属性注入 builder2.Register<Man>(c => new Man { Age = "20" }).As<IPerson>().EnableInterfaceInterceptors(); //builder2.RegisterType<Man>().As<IPerson>().EnableInterfaceInterceptors(); builder2.RegisterType<Woman>().Named<IPerson>("Woman").EnableInterfaceInterceptors(); //方式二:在注册类型到容器的时候动态注入拦截器(去掉类型上的特性Attribute) //builder2.RegisterType<Man>().As<IPerson>().InterceptedBy(typeof(LogInterceptor)).EnableInterfaceInterceptors(); //builder2.RegisterType<Woman>().Named<IPerson>("Woman").InterceptedBy(typeof(LogInterceptor)).EnableInterfaceInterceptors(); using (var container = builder2.Build()) { //从容器获取对象 var Manager = container.Resolve<PersonManager>(); Manager.Say("管理员"); var Person = container.Resolve<IPerson>(); Person.Say("张三"); var Woman = container.ResolveNamed<IPerson>("Woman"); Woman.Say("王萌"); } Console.ReadLine(); #endregion } } }
Autofac三种生命周期:InstancePerLifetimeScope、SingleInstance、InstancePerDependency
InstancePerLifetimeScope:同一个Lifetime生成的对象是同一个实例
SingleInstance:单例模式,每次调用,都会使用同一个实例化的对象;每次都用同一个对象;
InstancePerDependency:默认模式,每次调用,都会重新实例化对象;每次请求都创建一个新的对象
//方式二:在注册类型到容器的时候动态注入拦截器(去掉类型上的特性Attribute) builder.RegisterType<Man>().As<IPerson>().InterceptedBy(typeof(LogInterceptor)).InstancePerLifetimeScope().EnableInterfaceInterceptors();
看下面运行结果图
1、InstancePerLifetimeScope
2、SingleInstance
3、InstancePerDependency
AsImplementedInterfaces() 是以接口方式进行注入,注入这些类的所有的公共接口作为服务(除了释放资源)
builder.RegisterAssemblyTypes 注册程序集中符合条件的类型
Assembly assembly = Assembly.Load(assemblyName); //Assembly assembly = this.GetType().GetTypeInfo().Assembly; builder.RegisterAssemblyTypes(assembly).Where(type => !type.IsInterface && !type.IsSealed && !type.IsAbstract && type.Name.EndsWith("BLL", StringComparison.OrdinalIgnoreCase)) .AsImplementedInterfaces() .InstancePerLifetimeScope() .EnableInterfaceInterceptors() .InterceptedBy(typeof(LogInterceptor));
每个RegisterAssemblyTypes()
调用将仅应用一组规则 - 如果要注册多个不同组的组件,则需要多次调用RegisterAssemblyTypes()