zoukankan      html  css  js  c++  java
  • 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()

  • 相关阅读:
    session的工作原理
    jsp与servlet
    java对象的克隆以及深拷贝与浅拷贝
    vi和vim编辑器
    远程登录Linux系统(使用xshell),远程上传加载文件(使用Xftp)
    Linux目录结构(目录结构详解是重点)
    虚拟机CentOS克隆
    虚拟机CentOS创建/使用快照
    VMware Tools安装
    VM配置Centos(第十三步分区设置)
  • 原文地址:https://www.cnblogs.com/li150dan/p/10071079.html
Copyright © 2011-2022 走看看