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 = "" }).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的更多相关文章
- Spring之控制反转——IoC、面向切面编程——AOP
控制反转——IoC 提出IoC的目的 为了解决对象之间的耦合度过高的问题,提出了IoC理论,用来实现对象之间的解耦. 什么是IoC IoC是Inversion of Control的缩写,译为控制 ...
- 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 ...
- Spring框架使用(控制反转,依赖注入,面向切面AOP)
参见:http://blog.csdn.net/fei641327936/article/details/52015121 Mybatis: 实现IOC的轻量级的一个Bean的容器 Inversion ...
- 程序员笔记|Spring IoC、面向切面编程、事务管理等Spring基本概念详解
一.Spring IoC 1.1 重要概念 1)控制反转(Inversion of control) 控制反转是一种通过描述(在java中通过xml或者注解)并通过第三方去产生或获取特定对象的方式. ...
- Spring框架系列(3) - 深入浅出Spring核心之控制反转(IOC)
在Spring基础 - Spring简单例子引入Spring的核心中向你展示了IoC的基础含义,同时以此发散了一些IoC相关知识点; 本节将在此基础上进一步解读IOC的含义以及IOC的使用方式.@pd ...
- ASP.NET MVC 中 Autofac依赖注入DI 控制反转IOC 了解一下
先简单了解一这个几个 名词的意思. 控制反转(IOC) 依赖注入(DI) 并不是某种技术. 而是一种思想.一种面向对象编程法则 什么是控制反转(IOC)? 什么是依赖注入(DI) 可以点击下面链接 ...
- 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, ...
- C#依赖注入控制反转IOC实现详解
原文:C#依赖注入控制反转IOC实现详解 IOC的基本概念是:不创建对象,但是描述创建它们的方式.在代码中不直接与对象和服务连接,但在配置文件中描述哪一个组件需要哪一项服务.容器负责将这些联系在一起. ...
- 控制反转IoC简介
控制反转IoC简介 在实际的应用开发中,我们需要尽量避免和降低对象间的依赖关系,即降低耦合度.通常的业务对象之间都是互相依赖的,业务对象与业务对象.业务对象与持久层.业务对象与各种资源之间都存在这样或 ...
随机推荐
- Excel 截取字符,判断县区 城市。
https://jingyan.baidu.com/article/624e7459aa90e434e8ba5a8a.html https://jingyan.baidu.com/article/9f ...
- Honk's pool[STL multiset]
目录 题目地址 题干 代码和解释 题目地址 Honk's pool(The Preliminary Contest for ICPC Asia Shenyang 2019 ) 题干 代码和解释 本题使 ...
- JavaScript初探系列(九)——BOM
一.什么是BOM? BOM:Browser Object Model 是浏览器对象模型,浏览器对象模型提供了独立与内容的.可以与浏览器窗口进行互动的对象结构,BOM由多个对象构成,其中代表浏览器窗口的 ...
- 使用SpringEL功能来动态化模板数据
在类似excel导出功能里,如果excel的格式很复杂,通过程序去动态生成格式显然是很吃力的,我们可以采用模板文件+动态表达式占位来生成目标文件. 如果只是纯粹生成纯文本,使用freemarker等模 ...
- pandas连接多个表格concat()函数
网易云课堂该课程链接地址 https://study.163.com/course/courseMain.htm?share=2&shareId=400000000398149&cou ...
- Win10如何开启蓝屏记录?Win10开启蓝屏信息记录的方法
转载:http://www.xitongzhijia.net/xtjc/20170127/91010.html 蓝屏,是电脑最常见的故障,一般出现蓝屏时都会显示详细的蓝屏错误信息,方便用户排查故障.最 ...
- [PHP] dompdf 使用记录
# 安装字体,解决中文乱码参考: https://blog.51cto.com/lampzxr/1916038```首先下载composer curl -sS https://getcomposer. ...
- Centos7中rc.local设置springboot项目开机自启动
在Centos7下,rc.local文件,开机默认是不执行的 1.进入rc.local中 路径如下图
- golang xorm时区问题
mysql连接后面加 &loc=Local 否则执行sql的时间格式,存到数据库会按0时区 UTC存储
- 最常见的Java面试题及答案汇总(六)
异常 74. throw 和 throws 的区别? throws是用来声明一个方法可能抛出的所有异常信息,throws是将异常声明但是不处理,而是将异常往上传,谁调用我就交给谁处理.而throw则是 ...