关于spring.net的面向切面编程 (Aspect Oriented Programming with Spring.NET)-切入点(pointcut)API
本文翻译自Spring.NET官方文档Version 1.3.2。
受限于个人知识水平,有些地方翻译可能不准确,但是我还是希望我的这些微薄的努力能为他人提供帮助。
侵删。
让我们看看 Spring.NET 如何处理一些重要的关于切入点的概念。
一些概念
Spring.NET的切入点和通知是相互独立的,因此针对不同的通知类型可以使用相同的切入点。
Spring.Aop.IPointcut 接口是最核心的,是用来将通知定位到特定的类型或者方法,接口细节如下:
public interface IPointcut
{
ITypeFilter TypeFilter { get; }
IMethodMatcher MethodMatcher { get; }
}
将IPointcut 接口拆分成两个部分可以复用类型、方法匹配的功能和一些细粒度的操作(例如和其他方法匹配器(method matcher)的“union”操作)。
ITypeFilter 接口被用来将切入点限定到一系列的目标类型上。如果Matches() 方法全部返回true,那么所有的目标类型就都匹配上了:
public interface ITypeFilter
{
bool Matches(Type type);
}
IMethodMatcher 接口一般来说更加重要,完整的接口定义如下:
public interface IMethodMatcher
{
bool IsRuntime { get; }
bool Matches(MethodInfo method, Type targetType);
bool Matches(MethodInfo method, Type targetType, object[] args);
}
Matches(MethodInfo, Type)方法是用来测试这个切入点会不会匹配一个目标类中的特定方法。这种判断会在AOP代理生成的时候进行,而不是在每次方法调用的时候都进行一次。如果一个特定的方法在两个参数的匹配方法中匹配成功,并且IMethodMatcher 的IsRuntime 属性返回true,那么那个三个参数的方法就会在每一次 方法调用的时候被调用。这样,切入点就能在每次目标通知执行之前查看传入方法的参数。
大多IMethodMatchers 都是静态的,意味着他们的IsRuntime属性总是返回false。在这种情况下,三个参数的方法就不会被调用。所以如果有可能的话,尽量使用静态的切入点,因为AOP框架会在AOP代理产生的时候缓存这些切入点的判断结果。
关于切入点的一些操作
Spring.NET支持切入点的一些操作有:例如,union和intersection
union意味着方法中至少有一个符合切入点。
intersection意味着方法所有的切入点都符合。
union通常更有用。
切入点可以通过Spring.Aop.Support.Pointcuts 类中的静态方法结合,也可以使用在同一命名空间下的ComposablePointcut 类结合。
一些切入点的便捷应用
Spring.NET提供了一些便捷的切入点使用方式。一些可以直接使用,其他的可以作为各个应用特定的切入点的子类来应用。
静态切入点
静态切入点是以方法和目标类为基础,不考虑方法的传入参数。静态切入点足够应付,并且是最适合,大多的使用场景。这样,Spring.NET只要在一个方法第一次调用的时候判断一次切入点,在这个之后就不需要再每次调用的时候都进行判断了。
让我们考虑一些静态切入点在Spring.NET 中的使用场景:
使用正则表达式
一个常见的描述静态切入点使用的是正则表达式。包括Spring.NET,大部分的AOP框架都已经实现这个功能。Spring.Aop.Support.SdkRegularExpressionMethodPointcut是一个泛型的正则切入点,使用了.NET BCL中的正则类。
使用这个类,你可以先提供一系列的模式字符串(pattern Strings)。只要一个规则满足,这个切入点就会被判断为true(所以结果是这些切入点的union的操作结果)。匹配通过类的全名来判断,因此你可以使用这个切入点在任意的命名空间下的任何类中应用通知。
以下是一个使用场景:
<object id="settersAndAbsquatulatePointcut"
type="Spring.Aop.Support.SdkRegularExpressionMethodPointcut, Spring.Aop">
<property name="patterns">
<list>
<value>.*set.*</value>
<value>.*absquatulate</value>
</list>
</property>
</object>
为了方便,Spring为我们提供了RegularExpressionMethodPointcutAdvisor类来引用一个IAdvice接口实例,同时定义切入点规则(要记住IAdvice实例可以是一个拦截器,前置通知,异常通知等等)。这种简化的写法,把切入点和通知器写在同一个object标签里面,例如这样:
<object id="settersAndAbsquatulateAdvisor"
type="Spring.Aop.Support.RegularExpressionMethodPointcutAdvisor, Spring.Aop">
<property name="advice">
<ref local="objectNameOfAopAllianceInterceptor"/>
</property>
<property name="patterns">
<list>
<value>.*set.*</value>
<value>.*absquatulate</value>
</list>
</property>
</object>
RegularExpressionMethodPointcutAdvisor类可以作为任何的通知类型。如果你只有一个规则你可以使用这个属性名字规则然后为其特定一个值而不是定义所有的属性规则然后配上一个值列表。
你也可能从System.Text.RegularExpressions 命名空间下指定一个正则对象。内置的RegexConverter类将会提供解析。可以看6.4节, “Built-in TypeConverters”以找到更多的Spring内置类型转换器。正则对象在IoC容器中被创建成其他的任意对象。通过使用一个内部对象定义是一个很方便的方法来使定义和PointcutAdvisor声明更加接近。需要注意的是,如果在构造器中没有任何显式的指定的话,SdkRegularExpressionMethodPointcut类有一个默认配置属性来设置正则表达式的配置。
使用特性标签
切入点可以通过方法上面的特性(attribute)来指定。切入点关联的通知接下来就会通过解析特性标签来配置。AttributeMatchMethodPointCut类提供这种功能。以下例子中的切入点可以匹配所有的带有Spring.Attributes.CacheAttribute特性的标签方法:
<object id="cachePointcut" type="Spring.Aop.Support.AttributeMatchMethodPointcut, Spring.Aop">
<property name="Attribute" value="Spring.Attributes.CacheAttribute, Spring.Core"/>
</object>
就像下面展示的一样,这种方式也可以和DefaultPointcutAdvisor一起使用
<object id="cacheAspect" type="Spring.Aop.Support.DefaultPointcutAdvisor, Spring.Aop">
<property name="Pointcut">
<object type="Spring.Aop.Support.AttributeMatchMethodPointcut, Spring.Aop">
<property name="Attribute" value="Spring.Attributes.CacheAttribute, Spring.Core"/>
</object>
</property>
<property name="Advice" ref="aspNetCacheAdvice"/>
</object>
这里的aspNetCacheAdvice 是一个IMethodInterceptor 接口的实现,它缓存了方法的返回值。可以查阅SDK文档Spring.Aop.Advice.CacheAdvice 来获得更多与这个通知相关的信息。
为了方便,AttributeMatchMethodPointcutAdvisor 类定义另一种基于特性,更加简练的泛型DefaultPointcutAdvisor类通知器。以下是一个例子:
<object id="AspNetCacheAdvice" type="Spring.Aop.Support.AttributeMatchMethodPointcutAdvisor, Spring.Aop">
<property name="advice">
<object type="Aspect.AspNetCacheAdvice, Aspect"/>
</property>
<property name="attribute" value="Framework.AspNetCacheAttribute, Framework" />
</object>
动态切入点
动态切入点要比静态切入点更加耗费性能。他们要考虑方法的传入参数和静态的信息。这就意味着他们必须判断每一个方法的调用,这种判断结果是不能被缓存的,因为传入的参数多种多样。
一个常见的例子就是控制流切入点(control flow pointcut)。
控制流切入点
Spring.NET控制流切入点在概念上类似于AspectJ 的cflow切入点,尽管没有它那么强大。(当前无法指定一个切入点在其他切入点下执行)。一个控制流切入点肯定是动态的,这因为它要根据现在的每个方法调用时候的调用堆栈来判断。例如,一个类型A的方法A() 调用了类型B的方法B(),然后类型B的方法B()就在类型A的方法A()的控制流中执行。仅当类型B的方法B()被调用的时候,控制流切入点就能应用在类型A的方法A() ,而不是类型A的方法A() 在其他调用堆栈中执行。控制流切入点在Spring.Aop.Support.ControlFlowPointcut 类中详细定义。
当使用控制流切入点的时候,需要注意一些问题。在运行时,JIT编译器会内联一些方法,主要是为了提升性能,但是这会导致这个方法会在调用堆栈中消失。这是因为内联操作把被调用者的IL代码插入到调用者的IL代码中来有效地移除方法调用。这些信息可以从System.Diagnostics.StackTrace中获得,这样的话使用ControlFlowPointcut就会受到这些优化的影响而不匹配,这是因为这些方法被内联了。
总的来说,一个足够小的方法,可能只有几行代码(IL代码小于32 bytes)容易被内联。对于这个感兴趣的可以读David Notario的博客(JIT Optimizations I and JIT Optimizations II)。并且,当一个程序集按照发布模式的配置被编译的时候,元数据会告知CLR使用JIT优化。当按照调试模式的配置的时候,CLR会禁用(可能一些)JIT优化。根据以往经验来说,在调试模式下JIT是会关闭内联的。
一个保证你的控制流切入点不会被忽略的方法是使用System.Runtime.CompilerServices.MethodImplAttribute特性,然后将其赋值为MethodImplOptions.NoInlining。在这个简单的例子中,如果代码在发行模式中编译就不会匹配到“GetAge”方法。
public int GetAge(IPerson person)
{
return person.GetAge();
}
而且,使用上面的特性方法会在发行编译中不会进行内联。
[MethodImpl(MethodImplOptions.NoInlining)]
public int GetAge(IPerson person)
{
return person.GetAge();
}
自定义切入点
由于Spring.NET 中的切入点都是.NET 的基础类型,而不是基于语言的特征(language features )(例如在AspectJ中),因此无论对于静态切入点还是动态切入点,都可以声明自定义切入点。然而在AspectJ语法中, 现在却没有现成、成熟的自定义切入点的声明方式。在Spring.NET 中,自定义切入点就像一般实体模型一样可以被任意地关联调用。
Spring.NET 提供了有效的切入点的超类来支持你自定义切入点的实现。
因为静态切入点是最常见并且最有用的切入点类型,你只要继承StaticMethodMatcherPointcut,就像下面展示的那样,你只要实现一个抽象方法就行(尽管也可以重写其他方法来自定义行为):
public class TestStaticPointcut : StaticMethodMatcherPointcut {
public override bool Matches(MethodInfo method, Type targetType) {
// return true if custom criteria match
}
}
关于spring.net的面向切面编程 (Aspect Oriented Programming with Spring.NET)-切入点(pointcut)API的更多相关文章
- 关于spring.net的面向切面编程 (Aspect Oriented Programming with Spring.NET)-简介
本文翻译自Spring.NET官方文档Version 1.3.2. 受限于个人知识水平,有些地方翻译可能不准确,但是我还是希望我的这些微薄的努力能为他人提供帮助. 侵删. 简介 Aspect-Orie ...
- 关于spring.net的面向切面编程 (Aspect Oriented Programming with Spring.NET)-使用工厂创建代理(Using the ProxyFactoryObject to create AOP proxies)
本文翻译自Spring.NET官方文档Version 1.3.2. 受限于个人知识水平,有些地方翻译可能不准确,但是我还是希望我的这些微薄的努力能为他人提供帮助. 侵删. 如果你正在为你的业务模型使用 ...
- 关于spring.net的面向切面编程 (Aspect Oriented Programming with Spring.NET)-通知(Advice)API
本文翻译自Spring.NET官方文档Version 1.3.2. 受限于个人知识水平,有些地方翻译可能不准确,但是我还是希望我的这些微薄的努力能为他人提供帮助. 侵删. 让我们看看 Spring.N ...
- 面向切面编程 ( Aspect Oriented Programming with Spring )
Aspect Oriented Programming with Spring 1. 简介 AOP是与OOP不同的一种程序结构.在OOP编程中,模块的单位是class(类):然而,在AOP编程中模块的 ...
- 关于面向切面编程Aspect Oriented Programming(AOP)
最近学到spring ,出来了一个新概念,面向切面编程,下面做个笔记,引自百度百科. Aspect Oriented Programming(AOP),面向切面编程,是一个比较热门的话题.AOP主要实 ...
- javascript 高阶函数 实现 AOP 面向切面编程 Aspect Oriented Programming
AOP的主要作用是吧一些跟核心业务逻辑模块无关的功能 -日志统计, 安全控制, 异常处理- 抽离出来, 再通过"动态织入"的方式掺入业务逻辑模块中. 这里通过扩展Function. ...
- 程序员笔记|Spring IoC、面向切面编程、事务管理等Spring基本概念详解
一.Spring IoC 1.1 重要概念 1)控制反转(Inversion of control) 控制反转是一种通过描述(在java中通过xml或者注解)并通过第三方去产生或获取特定对象的方式. ...
- Spring框架系列(4) - 深入浅出Spring核心之面向切面编程(AOP)
在Spring基础 - Spring简单例子引入Spring的核心中向你展示了AOP的基础含义,同时以此发散了一些AOP相关知识点; 本节将在此基础上进一步解读AOP的含义以及AOP的使用方式.@pd ...
- Spring AOP:面向切面编程,AspectJ,是基于spring 的xml文件的方法
导包等不在赘述: 建立一个接口:ArithmeticCalculator,没有实例化的方法: package com.atguigu.spring.aop.impl.panpan; public in ...
随机推荐
- jquery实现各种实例
1.正反选实例 <!DOCTYPE html> <html lang="en"> <head> <meta charset="U ...
- v-if与v-show区别
在v-show中,元素是一直存在的,当v-show为false时,元素display:none只是隐藏了而已. v-if 作用:判断是否加载固定的内容,如果为真,则加载:为假时,则不加载. 用处:用在 ...
- hdu 2510 符号三角形 (DFS+打表)
符号三角形 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submi ...
- [洛谷P2613]【模板】有理数取余
题目大意:给你$a,b(a,b\leqslant10^{10001})$,求出$\dfrac a b\equiv1\pmod{19260817}$,无解输出 Angry! 题解:在读入的时候取模,若$ ...
- 《R语言实战》读书笔记--为什么要学
本人最近在某咨询公司实习,涉及到了一些数据分析的工作,用的是R语言来处理数据.但是在应用的过程中,发现用R很不熟练,所以再打算学一遍R.曾经花一个月的时间看过一遍<R语言编程艺术>,还用R ...
- nginx支持pathinfo
server { root /webserver/www/api; listen ; server_name api.dnxia.com; location / { if (!-e $request_ ...
- bigdecimal的使用
BigDecimal 由任意精度的整数非标度值 和 32 位的整数标度 (scale) 组成.如果为零或正数,则标度是小数点后的位数.如果为负数,则将该数的非标度值乘以 10 的负 scale 次幂. ...
- spring in action 学习笔记五:@Autowired这个注解如何理解
@Autowired这个注解的意思就是自动装配.他把一个bean对象自动装配到另一个对象中.下面的案例证明了spring的自动装配. 定义一个Sixi类.代码如下: package com.qls.a ...
- Cisco IPC Emergency Responder Error
Upon startup of the newer Cisco IP Communicator clients (especially on Windows Vista/7), sometimes y ...
- 经典linux书籍
入门篇<LINUX权威指南>书不错,写的很全面也比较广,涉及的不深,做为入门书籍不错,可以比较全面的了解linux .另外比较热门的也可以看看<鸟哥的私房菜>等书,偏管理类的书 ...