AOP专题
Spring的AOP实现
前面我们阐述了动态代理实现AOP机制。 现在看看Spring如何实现AOP的。
AOP的几个名词:
- Pointcut类似触发器,是事件Event发生源,一旦pointcut被触发,将会产生相应的动作Action,这部分Action称为Advice。
- Advice在AspectJ有三种:before、 after、Around之分 。Advice分:
(1) Interceptor 是拦截器,动态代理做拦截器。
(2). Introduction修改一个类,以增加字段、方法或构造或者执行新的接口,包括Mixin实现 - AOP是将通用功能和特殊功能在编码时期分离,在运行时刻需要装配,这个阶段称为weaving
instrumentor - 用来实现weaving功能的工具。
结合前面动态代理实现,Advice相当于DynamicProxyTemplate这个类,它调用拦截器,然后在被拦截的目标对象之前或之后执行:
interceptor.beforeAction(method, args);//这里是一个joinpoint
o = method.invoke(obj, args);//BuinessOne.mymethod();
interceptor.afterAction(method, args);;//这里是一个joinpoint
不过在Spring中,这段拦截位置是在XML配置或元注解中配置的,更加灵活。如下图:
下面结合Spring,对AOP用语进行详细总结如下:
- 切入点(Joinpoint): 程序执行的某个特定位置,如类的初始化前后、方法的调用前后、抛异常后。Spring只支持方法切入点。
- 切面(Pointcut): Spring中通过org.springframework.aop.Pointcut进行描述
- 激活与处理(Advice): 植入到目标切入点上的一段程序。Spring提供的接口都带有方位名:BeforeAdvice,AfterReturnAdvice,ThrowsAdvice。
- 目标(Target): 切入的逻辑植入的目标类
- 引入(Introduction): 一种特殊的Advice,可以为类添加一些属性和方法
- 织入(Weaving): 将Advice与连接点结合的方法.Spring使用动态代理实现,AspectJ在编译时和类加载时实现。
- 方面(Aspect):
Pointcut+Advice
Spring的AOP实现内部机制:
- J2SE 动态代理
使用到的类:Proxy,InvocationHandler
使用interception chain实现Advice。
只能对接口进行代理
- CGLIB 代理(第三方库 性能快)
可以直接对Class进行代理
- AspectJ 需要用特定的Java编译器,在编译时混合代码。
Spring的AOP类图:
下面我们看看Spring的Pointcuts切入点这个类;
Pointcuts有两个方法:
- 将advice固定于某个特定的类ClassFilter,这是用来寻找匹配被拦截的类
- MethodMatcher是寻找被拦截的目标对象方法是否和需要拦截的方法一致。matches(Method, Class) 方法通常用于测试pointcut是否和目标类的方法匹配. 它是在AOP proxy 被创建时执行,这样可以避免每次方法调用都进行测试执行。最后一个matches是每次方法调用时都被执行
切入面有两种:
- 静态切入面:
(1).NameMatchMethod 根据方法名字切入
(2).根据方法的正则表法式切入 - 动态切入面
静态切入pointcuts
代码:
相应配置:
正则表达式切入法
- <bean id="settersAndAbsquatulateAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<ref local="beanNameOfAopAllianceInterceptor"/> </property>
<property name="patterns">
<list>
<value>.*get.*</value>
<value>.*absquatulate</value>
</list>
</property>
</bean>
凡是方法名匹配value中字符串,使用advice为XXInterceptor实现拦截。
正则表达式切入法另外一个案例:
正则表达式中匹配规则:
动态切入面pointcuts
- 需要在运行时进行动态切入。
- 提供ControlFlowPointcut,这个pointcut将基于线程的调用栈Stack信息
- 如果发现一个类或方法被当前Stack调用,就被拦截执行切入。
案例代码: