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();
        }
    }
}
View Code

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 !" );
        }
    }
}
View Code
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      
        }
    }
}
View Code

第二种:接口代理拦截

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);
    }
}
View Code
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);
        }
    }
}
View Code
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            
        }
    }
}
View Code

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()

posted @ 2018-12-05 15:14  以德为先  阅读(9368)  评论(2编辑  收藏  举报