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简介 在实际的应用开发中,我们需要尽量避免和降低对象间的依赖关系,即降低耦合度.通常的业务对象之间都是互相依赖的,业务对象与业务对象.业务对象与持久层.业务对象与各种资源之间都存在这样或 ...
随机推荐
- 面试官问我:平常如何对你的 Java 程序进行调优?
阅读本文大概需要 10 分钟. 作者:张俊城, 郭理勇, 刘建来源:http://t.cn/AiCTERJz Java 应用性能优化是一个老生常谈的话题,典型的性能问题如页面响应慢.接口超时,服务器负 ...
- 图上的并行处理 Parallel Processing of Graphs
Graph 本次学术前沿讲座由邵斌老师主讲,标题已经揭示了主题:Graph.1.5h的talk,听完自觉意犹未尽.本来以为是一节自己没接触过的图形学的talk,没想到讲的很多内容都跟自己学过的很多东西 ...
- [Beta]Scrum Meeting#6
github 本次会议项目由PM召开,时间为5月11日晚上10点30分 时长15分钟 任务表格 人员 昨日工作 下一步工作 木鬼 撰写博客整理文档 撰写博客整理文档 swoip 改进界面 为适应新功能 ...
- linux安装yasm报错
进入yasm-1.2.0, 输入指令 ./configure //编译yasm make && make install //安装yasm,安装完成即可. 报错信息 make[2]: ...
- httpcomponents 发送get post请求
引入的包为: <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient --> <de ...
- mysql时间和本地时间相差13个小时的问题
首先需要查看mysql的当前时区,用time_zone参数 mysql> show variables like '%time_zone%'; +------------------+----- ...
- IfcCircle
An IfcCircle is a curve consisting of a set of points having equal distance from the center. NOTE A ...
- Invalid prop: custom validator check failed for prop "pagination" <Table> vue.runtime.esm
错误如图 原因,返回数据中没有包括分布的属性
- 拼接Sql语句小心得
在往数据库插入数据时,需要根据数据和数据库中的列信息进行拼接,在本篇文章中,输出小心得.使用语言为 python. 拼接原始列信息 比如待插入数据库列信息为 deptNo,dName, Locate, ...
- Ubuntu16.04安装Supervisor
安装 sudo apt-get install supervisor 启动,否则会报 unix:///tmp/supervisor.sock no such file service supervis ...