本文翻译自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的更多相关文章

  1. 关于spring.net的面向切面编程 (Aspect Oriented Programming with Spring.NET)-简介

    本文翻译自Spring.NET官方文档Version 1.3.2. 受限于个人知识水平,有些地方翻译可能不准确,但是我还是希望我的这些微薄的努力能为他人提供帮助. 侵删. 简介 Aspect-Orie ...

  2. 关于spring.net的面向切面编程 (Aspect Oriented Programming with Spring.NET)-使用工厂创建代理(Using the ProxyFactoryObject to create AOP proxies)

    本文翻译自Spring.NET官方文档Version 1.3.2. 受限于个人知识水平,有些地方翻译可能不准确,但是我还是希望我的这些微薄的努力能为他人提供帮助. 侵删. 如果你正在为你的业务模型使用 ...

  3. 关于spring.net的面向切面编程 (Aspect Oriented Programming with Spring.NET)-通知(Advice)API

    本文翻译自Spring.NET官方文档Version 1.3.2. 受限于个人知识水平,有些地方翻译可能不准确,但是我还是希望我的这些微薄的努力能为他人提供帮助. 侵删. 让我们看看 Spring.N ...

  4. 面向切面编程 ( Aspect Oriented Programming with Spring )

    Aspect Oriented Programming with Spring 1. 简介 AOP是与OOP不同的一种程序结构.在OOP编程中,模块的单位是class(类):然而,在AOP编程中模块的 ...

  5. 关于面向切面编程Aspect Oriented Programming(AOP)

    最近学到spring ,出来了一个新概念,面向切面编程,下面做个笔记,引自百度百科. Aspect Oriented Programming(AOP),面向切面编程,是一个比较热门的话题.AOP主要实 ...

  6. javascript 高阶函数 实现 AOP 面向切面编程 Aspect Oriented Programming

    AOP的主要作用是吧一些跟核心业务逻辑模块无关的功能 -日志统计, 安全控制, 异常处理- 抽离出来, 再通过"动态织入"的方式掺入业务逻辑模块中. 这里通过扩展Function. ...

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

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

  8. Spring框架系列(4) - 深入浅出Spring核心之面向切面编程(AOP)

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

  9. Spring AOP:面向切面编程,AspectJ,是基于spring 的xml文件的方法

    导包等不在赘述: 建立一个接口:ArithmeticCalculator,没有实例化的方法: package com.atguigu.spring.aop.impl.panpan; public in ...

随机推荐

  1. 台州学院we are without brain 训练 后缀数组

    sa[i]表示排名为 i 的后缀的第一个字符在原串中的位置 rank[i]表示按照从小到大排名  以i为下标开始的后缀的排名 height[i]表示排名为 i 和排名为 i+1的后缀的最长公共前缀的长 ...

  2. java案例1,打印hello java

    package anli1; public class hellojava { public static void main(String []args){ System.out.println(& ...

  3. hadoop 客户的的使用

    ${HADOOP_HOME}/bin/hadoop job Usage: JobClient <command> <args> [-submit <job-file> ...

  4. Android通过onDraw实现在View中绘图操作

    Android绘图操作,通过继承View实现,在onDraw函数中实现绘图. 下面是一个简单的例子: public class AndroidTest extends Activity { /** C ...

  5. sql的over函数的使用

    over不能单独使用,要和分析函数:rank(),dense_rank(),row_number()等一起使用.其参数:over(partition by columnname1 order by c ...

  6. Python实现队列

    队列的数据结构的主要结构:一个结点类和两个方法:出队列和进队列 class Node(object): def __init__(self,val): self.val = val self.next ...

  7. B-number(hdu 3652)

    题意:找出1~n范围内含有13并且能被13整除的数字的个数 /* 数位DP dp[i][j][0]表示i位数模13为j当前没有包含13并且最高位不为1的方案数: dp[i][j][0]表示i位数模13 ...

  8. poj2728 最小比率生成树——01分数规划

    题目大意: 有n个村庄,村庄在不同坐标和海拔,现在要对所有村庄供水, 只要两个村庄之间有一条路即可,建造水管距离为坐标之间的欧几里德距离,费用为海拔之差, 现在要求方案使得费用与距离的比值最小,很显然 ...

  9. QLineEdit使用总结(转)

    本文转自 https://www.cnblogs.com/hellovenus/p/5183593.html

  10. How to duplicate a UIButton in Objective C?

    http://stackoverflow.com/questions/1092875/how-to-duplicate-a-uibutton-in-objective-c 1down vote To ...