Autofac的切面编程实现

面向切面编程:Autofac.Annotation扩展组件是我开源的一款利用打标签完成autofac容器的注入组件。

https://github.com/yuzd/Autofac.Annotation

我们之前介绍了利用Aspect标签来完成拦截器功能

Aspect是一对一的方式,我想要某个class开启拦截器功能我需要针对每个class去配置。 详情请点击

比如说 我有2个 controller 每个controller都有2个action方法,

[Component]public class ProductController{public virtual string GetProduct(string productId){return "GetProduct:" + productId;}public virtual string UpdateProduct(string productId){return "UpdateProduct:" + productId;}}[Component]public class UserController{public virtual string GetUser(string userId){return "GetUser:" + userId;}public virtual string DeleteUser(string userId){return "DeleteUser:" + userId;}}

如果我需要这2个controller的action方法都在执行方法前打log 在方法执行后打log 按照上一节Aspect的话 我需要每个controller都要配置。如果我有100个controller的画我就需要配置100次,这样我觉得太麻烦了。所以我参考了Spring的Pointcut切面编程的方式实现了一套类似的,下面看如何用Pointcut的方式方便的配置一种切面去适用于N个对象。

定义一个切面:创建一个class 上面打上Pointcut的标签 如下:

Pointcut标签类有如下属性:

属性名说明
Name名称Pointcut切面的名称(默认为空,和拦截方法进行匹配,参考下面说明)
RetType匹配目标类的方法的返回类型(默认是%)
NameSpace匹配目标类的namespace(默认是%)
ClassName匹配目标类的类名称(必填)
MethodName匹配目标类的方法名称(默认是%)

匹配算法

 举例:

匹配结果匹配模板要匹配的字符串
匹配结果:true"%"""
匹配结果:true"%"" "
匹配结果:true"%""asdfa asdf asdf"
匹配结果:true"%""%"
匹配结果:false"_"""
匹配结果:true"_"" "
匹配结果:true"_""4"
匹配结果:true"_""C"
匹配结果:false"_""CX"
匹配结果:false"[ABCD]"""
匹配结果:true"[ABCD]""A"
匹配结果:true"[ABCD]""b"
匹配结果:false"[ABCD]""X"
匹配结果:false"[ABCD]""AB"
匹配结果:true"[B-D]""C"
匹配结果:true"[B-D]""D"
匹配结果:false"[B-D]""A"
匹配结果:false"[^B-D]""C"
匹配结果:false"[^B-D]""D"
匹配结果:true"[^B-D]""A"
匹配结果:true"%TEST[ABCD]XXX""lolTESTBXXX"
匹配结果:false"%TEST[ABCD]XXX""lolTESTZXXX"
匹配结果:false"%TEST[^ABCD]XXX""lolTESTBXXX"
匹配结果:true"%TEST[^ABCD]XXX""lolTESTZXXX"
匹配结果:true"%TEST[B-D]XXX""lolTESTBXXX"
匹配结果:true"%TEST[^B-D]XXX""lolTESTZXXX"
匹配结果:true"%Stuff.txt""Stuff.txt"
匹配结果:true"%Stuff.txt""MagicStuff.txt"
匹配结果:false"%Stuff.txt""MagicStuff.txt.img"
匹配结果:false"%Stuff.txt""Stuff.txt.img"
匹配结果:false"%Stuff.txt""MagicStuff001.txt.img"
匹配结果:true"Stuff.txt%""Stuff.txt"
匹配结果:false"Stuff.txt%""MagicStuff.txt"
匹配结果:false"Stuff.txt%""MagicStuff.txt.img"
匹配结果:true"Stuff.txt%""Stuff.txt.img"
匹配结果:false"Stuff.txt%""MagicStuff001.txt.img"
匹配结果:true"%Stuff.txt%""Stuff.txt"
匹配结果:true"%Stuff.txt%""MagicStuff.txt"
匹配结果:true"%Stuff.txt%""MagicStuff.txt.img"
匹配结果:true"%Stuff.txt%""Stuff.txt.img"
匹配结果:false"%Stuff.txt%""MagicStuff001.txt.img"
匹配结果:true"%Stuff%.txt""Stuff.txt"
匹配结果:true"%Stuff%.txt""MagicStuff.txt"
匹配结果:false"%Stuff%.txt""MagicStuff.txt.img"
匹配结果:false"%Stuff%.txt""Stuff.txt.img"
匹配结果:false"%Stuff%.txt""MagicStuff001.txt.img"
匹配结果:true"%Stuff%.txt""MagicStuff001.txt"
匹配结果:true"Stuff%.txt%""Stuff.txt"
匹配结果:false"Stuff%.txt%""MagicStuff.txt"
匹配结果:false"Stuff%.txt%""MagicStuff.txt.img"
匹配结果:true"Stuff%.txt%""Stuff.txt.img"
匹配结果:false"Stuff%.txt%""MagicStuff001.txt.img"
匹配结果:false"Stuff%.txt%""MagicStuff001.txt"
匹配结果:true"%Stuff%.txt%""Stuff.txt"
匹配结果:true"%Stuff%.txt%""MagicStuff.txt"
匹配结果:true"%Stuff%.txt%""MagicStuff.txt.img"
匹配结果:true"%Stuff%.txt%""Stuff.txt.img"
匹配结果:true"%Stuff%.txt%""MagicStuff001.txt.img"
匹配结果:true"%Stuff%.txt%""MagicStuff001.txt"
匹配结果:true"?Stuff?.txt?""1Stuff3.txt4"
匹配结果:false"?Stuff?.txt?""1Stuff.txt4"
匹配结果:false"?Stuff?.txt?""1Stuff3.txt"
匹配结果:false"?Stuff?.txt?""Stuff3.txt4"
// *Controller 代表匹配 只要是Controller结尾的类都能匹配// Get* 代表上面匹配成功的类下 所以是Get打头的方法都能匹配[Pointcut(ClassName = "*Controller",MethodName = "Get*")]public class LoggerPointCut{}

定义好了一个Pointcut切面后 需要定义这个切面的拦截方法

配合Pointcut切面标签,可以在打了这个标签的class下定义拦截方法, 在方法上得打上特定的标签,有如下几种:

切面执行方法上打标签种类说明
Before标签在匹配成功的类的方法执行前执行
After标签在匹配成功的类的方法执行后执行
Around标签承接了 匹配成功的类的方法的执行权(如果一个切面配置了Around又配置了Before或者After,那么会只执行Around)

以上3种标签有一个可选的参数:Name (默认为空,可以和Pointcut的Name进行mapping)

  • 因为一个class上可以打多个Pointcut切面,一个Pointcut切面可以根据name去匹配对应拦截方法

    // *Controller 代表匹配 只要是Controller结尾的类都能匹配// Get* 代表上面匹配成功的类下 所以是Get打头的方法都能匹配[Pointcut(ClassName = "*Controller",MethodName = "Get*")]public class LoggerPointCut{/// <summary>/// 打上Before标签 代表满足匹配的方法 在执行之前会执行下面的Before()方法/// </summary>[Before]public void Befor(){Console.WriteLine("before");}/// <summary>/// 打上After标签 代表满足匹配的方法 在执行之前会执行下面的After()方法/// </summary>[After]public void After(){Console.WriteLine("after");}}

如果是用Around环绕的话

// *Controller 代表匹配 只要是Controller结尾的类都能匹配// Get* 代表上面匹配成功的类下 所以是Get打头的方法都能匹配[Pointcut(ClassName = "*Controller",MethodName = "Get*")]public class LoggerPointCut{/// <summary>/// 打上Around标签 承接了 匹配成功的类的方法的执行权/// </summary>/// <param name="context"></param>[Around]public void Around(AspectContext context){//执行原目标方法前Console.WriteLine(context.InvocationContext.MethodInvocationTarget.Name + "-->Start");//执行原目标方法context.InvocationProceedInfo.Invoke();//执行原目标方法后Console.WriteLine(context.InvocationContext.MethodInvocationTarget.Name + "-->End");}}

执行方法的参数说明:

执行方法的参数可以是DI容器的类型,会在执行时自动注入进来,可以使用Autowired,Value等标签来修饰参数。

还有一个特殊的执行参数可以注入,那就是AspectContext,这个类型里面你可以获取到被拦截的方法的信息,以及执行原方法的委托。

注意:这个执行后 有2种

  • 正常执行成功

  • 有异常,若方法参数注入了AspectContext 那么可以通过Exception属性值获得异常内容

按照上面的配置

  • ProductController.GetProduct 会被匹配

  • UserController.GetUser 会被匹配

在执行上面这2个方法的时候会

  • 先执行 LoggerPointCut.Before方法

  • 再执行 LoggerPointCut.After方法

利用Autofac的这个开源扩展组件很方便的实现切面编程,总结切面编程三步骤

  • 1.定义一个切面,编写要匹配的目标类的方法(采用sql的like方式匹配),所以一个切面可以拦截n个目标

  • 2.定义对应的拦截方法

  • 3.执行被匹配的方法时会执行对应的拦截方法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/310195.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[Java基础]体验Lambda表达式

普通写法: 代码如下: package LambdaPack01;public class MyRunnable implements Runnable{Overridepublic void run() {System.out.println("多线程启动了");} }package LambdaPack01;public class LambdaDemo01 {public static void main(String[] args) {MyRunna…

linux启动mqtt_linux下安装MQTT服务器 - EMQTT

1. 下载从官网下载https://www.emqx.io/downloads#broker&#xff0c; 本文所用版本为broker/v3.2.1/emqx-centos7-v3.2.1.ziplinux下 下载:wget https://www.emqx.io/downloads/broker/v3.2.1/emqx-centos7-v3.2.1.zip解压&#xff1b;unzip emqx-centos7-v3.2.1.zip所在目录&…

.net core 基于Dapper 的分库分表开源框架(core-data)

一、前言感觉很久没写文章了&#xff0c;最近也比较忙&#xff0c;写的相对比较少&#xff0c;抽空分享基于Dapper 的分库分表开源框架core-data的强大功能&#xff0c;更好的提高开发过程中的效率&#xff1b;在数据库的数据日积月累的积累下&#xff0c;业务数据库中的单表数…

[Java基础]Lambda表达式练习

代码如下: package LambdaPracticePack;public interface Eatable {void eat(); }package LambdaPracticePack;public class EatableImpl implements Eatable{Overridepublic void eat() {System.out.println("一天一苹果&#xff0c;医生远离我");} }package Lambd…

​你可能不知道的7个HTML小技巧

五一期间&#xff0c;知道大家都比较懒&#xff0c;我也是。所以写篇简单且基础的技术小文&#xff0c;不需要动脑子&#xff0c;扫一眼就能掌握的那种。DETAILS 标签<details> 标签将额外的详情信息隐藏起来&#xff0c;用户在需要的时候点击即可展开查看详情。<deta…

青年节寄语和新课程免费上架

大家好&#xff0c;确实好久没有写东西了&#xff0c;希望这篇推送不是用来提醒你取消关注哈。2020年这突如其来的疫情&#xff0c;打乱了我们的生活&#xff0c;也让很多人更加明白了生活的无常以及可贵吧&#xff0c;在此也真诚希望大家都要好好哒&#xff0c;不负韶华&#…

从堆里找回“丢失”的代码相关命令简介

前言 在上一篇文章中&#xff0c;我们主要使用了三个命令 !address&#xff0c;s&#xff0c;.writemem 把丢失的代码成功的保存到了文件中。本文简单介绍一下上文用到的这三个命令。windbg 中的地址范围语法 很多命令都会用到 地址范围。比如 s 命令&#xff0c;.writemem 命令…

慎用ToLower和ToUpper,小心把你的系统给拖垮了

不知道何时开始&#xff0c;很多程序员喜欢用ToLower&#xff0c;ToUpper去实现忽略大小写模式的字符串相等性比较&#xff0c;有可能这个习惯是从别的语言引进的&#xff0c;大胆猜测下是JS&#xff0c;为了不引起争论&#xff0c;我指的JS是技师的意思~一&#xff1a;背景1. …

mysql 2008 日_SQL2008 的 日期数据类型

摘要你是否曾经想在数据库中存储一个日期而没有时间部分&#xff0c;或者想存储一个时间值希望有更高的精度&#xff1f;在SQL Server 2008的介绍中&#xff0c;微软介绍了一些新的日期数据类允许你只存储一个日期、更高精度的时间值等。这些新的数据类型为你存储日期和时间相关…

别了,JavaScript;你好,Blazor

Web开发与JavaScript开发向来是同义词。直到WebAssembly的横空出世&#xff0c;WebAssembly (Wasm)是一种在浏览器中可以执行的二进制指令。WebAssembly 的 官方工具链 能够编译 C/C 代码&#xff0c;但许多社区也提供了不同语言的编译器&#xff0c;如 Rust&#xff0c;Python…

[Java基础]接口组成(默认方法,静态方法,私有方法)

默认方法: 代码如下: package MyInterfacePack;public interface MyInterface {void show1();void show2();// void show3();public default void show3(){System.out.println("show3");};}package MyInterfacePack;public class MyInterfaceImplOne implements …

linux jdk1.7 tomcat mysql_Linux环境搭建 jdk+tomcat+mysql

好久之前搭建的&#xff0c;现在记录下 防止下次配置去找安装jdk(jre也行),tomcat MySQL一、jdk安装及环境变量配置:我是用 jdk-8u191-linux-x64.tar.gz 安装的安装之前提前下载好 jdk版本 看你用什么版本吧 都一样的步骤 按照下面的步骤操作 要确保完全是一个新环境…

开源 一套 Blazor Server 端精致套件

Blazor 作为一种 Web 开发的新技术已经发展有一段时间了&#xff0c;有些人标称 无 JS 无 TS&#xff0c;我觉得有点误导新人的意味&#xff0c;也有人文章大肆宣传 Blazor 是 JavaScript 的终结者&#xff0c;是为了替代 JavaScript 而生的&#xff0c;我认为这些言论都太激进…

[Java基础]函数式接口

代码如下: package MyInterfacePack01;FunctionalInterface public interface MyInterface {void show(); }package MyInterfacePack01;public class MyInterfaceDemo {public static void main(String[] args){MyInterface my ()->System.out.println("hello world&q…

从零搭建分布式文件系统MinIO比FastDFS要更合适

前两天跟大家分享了一篇关于如何利用FastDFS组件来自建分布式文件系统的文章&#xff0c;有兴趣的朋友可以阅读下《用asp.net core结合fastdfs打造分布式文件存储系统》。通过留言发现大家虽然感兴趣&#xff0c;但是都觉得部署比较麻烦。的确&#xff0c;fastdfs的部署很繁琐&…

[Java基础]方法引用

代码如下: package PrintablePack;public interface Printable {void printString(String s);}package PrintablePack;public class PrintableDemo {public static void main(String[] args){usePrintable(s-> System.out.println(s));usePrintable(System.out::println);/…