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 = "" }).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()

C#使用Autofac实现控制反转IoC和面向切面编程AOP的更多相关文章

  1. Spring之控制反转——IoC、面向切面编程——AOP

      控制反转——IoC 提出IoC的目的 为了解决对象之间的耦合度过高的问题,提出了IoC理论,用来实现对象之间的解耦. 什么是IoC IoC是Inversion of Control的缩写,译为控制 ...

  2. 04 Spring:01.Spring框架简介&&02.程序间耦合&&03.Spring的 IOC 和 DI&&08.面向切面编程 AOP&&10.Spring中事务控制

    spring共四天 第一天:spring框架的概述以及spring中基于XML的IOC配置 第二天:spring中基于注解的IOC和ioc的案例 第三天:spring中的aop和基于XML以及注解的A ...

  3. Spring框架使用(控制反转,依赖注入,面向切面AOP)

    参见:http://blog.csdn.net/fei641327936/article/details/52015121 Mybatis: 实现IOC的轻量级的一个Bean的容器 Inversion ...

  4. 程序员笔记|Spring IoC、面向切面编程、事务管理等Spring基本概念详解

    一.Spring IoC 1.1 重要概念 1)控制反转(Inversion of control) 控制反转是一种通过描述(在java中通过xml或者注解)并通过第三方去产生或获取特定对象的方式. ...

  5. Spring框架系列(3) - 深入浅出Spring核心之控制反转(IOC)

    在Spring基础 - Spring简单例子引入Spring的核心中向你展示了IoC的基础含义,同时以此发散了一些IoC相关知识点; 本节将在此基础上进一步解读IOC的含义以及IOC的使用方式.@pd ...

  6. ASP.NET MVC 中 Autofac依赖注入DI 控制反转IOC 了解一下

    先简单了解一这个几个 名词的意思. 控制反转(IOC) 依赖注入(DI) 并不是某种技术. 而是一种思想.一种面向对象编程法则 什么是控制反转(IOC)?  什么是依赖注入(DI) 可以点击下面链接 ...

  7. ADO.NET .net core2.0添加json文件并转化成类注入控制器使用 简单了解 iTextSharp实现HTML to PDF ASP.NET MVC 中 Autofac依赖注入DI 控制反转IOC 了解一下 C# AutoMapper 了解一下

    ADO.NET   一.ADO.NET概要 ADO.NET是.NET框架中的重要组件,主要用于完成C#应用程序访问数据库 二.ADO.NET的组成 ①System.Data  → DataTable, ...

  8. C#依赖注入控制反转IOC实现详解

    原文:C#依赖注入控制反转IOC实现详解 IOC的基本概念是:不创建对象,但是描述创建它们的方式.在代码中不直接与对象和服务连接,但在配置文件中描述哪一个组件需要哪一项服务.容器负责将这些联系在一起. ...

  9. 控制反转IoC简介

    控制反转IoC简介 在实际的应用开发中,我们需要尽量避免和降低对象间的依赖关系,即降低耦合度.通常的业务对象之间都是互相依赖的,业务对象与业务对象.业务对象与持久层.业务对象与各种资源之间都存在这样或 ...

随机推荐

  1. Excel 截取字符,判断县区 城市。

    https://jingyan.baidu.com/article/624e7459aa90e434e8ba5a8a.html https://jingyan.baidu.com/article/9f ...

  2. Honk's pool[STL multiset]

    目录 题目地址 题干 代码和解释 题目地址 Honk's pool(The Preliminary Contest for ICPC Asia Shenyang 2019 ) 题干 代码和解释 本题使 ...

  3. JavaScript初探系列(九)——BOM

    一.什么是BOM? BOM:Browser Object Model 是浏览器对象模型,浏览器对象模型提供了独立与内容的.可以与浏览器窗口进行互动的对象结构,BOM由多个对象构成,其中代表浏览器窗口的 ...

  4. 使用SpringEL功能来动态化模板数据

    在类似excel导出功能里,如果excel的格式很复杂,通过程序去动态生成格式显然是很吃力的,我们可以采用模板文件+动态表达式占位来生成目标文件. 如果只是纯粹生成纯文本,使用freemarker等模 ...

  5. pandas连接多个表格concat()函数

    网易云课堂该课程链接地址 https://study.163.com/course/courseMain.htm?share=2&shareId=400000000398149&cou ...

  6. Win10如何开启蓝屏记录?Win10开启蓝屏信息记录的方法

    转载:http://www.xitongzhijia.net/xtjc/20170127/91010.html 蓝屏,是电脑最常见的故障,一般出现蓝屏时都会显示详细的蓝屏错误信息,方便用户排查故障.最 ...

  7. [PHP] dompdf 使用记录

    # 安装字体,解决中文乱码参考: https://blog.51cto.com/lampzxr/1916038```首先下载composer curl -sS https://getcomposer. ...

  8. Centos7中rc.local设置springboot项目开机自启动

    在Centos7下,rc.local文件,开机默认是不执行的 1.进入rc.local中 路径如下图

  9. golang xorm时区问题

    mysql连接后面加 &loc=Local 否则执行sql的时间格式,存到数据库会按0时区 UTC存储

  10. 最常见的Java面试题及答案汇总(六)

    异常 74. throw 和 throws 的区别? throws是用来声明一个方法可能抛出的所有异常信息,throws是将异常声明但是不处理,而是将异常往上传,谁调用我就交给谁处理.而throw则是 ...