AOP是Aspect-Oriented Programming(面向方面编程或面向切面)的简称。
Aspect是一种新的模块化机制,用来描述分散在对象、类或函数中的横切关注点。从关注点中分离出横切关注点是面向切面的程序设计
的核心概念。分离关注点使解决特定问题的代码从业务逻辑中独立出来,业务逻辑的代码中不再含有针对特定领域问题代码的调用,业
务逻辑同特定领域问题的关系通过切面来封装、维护,这样原本分散在整个应用程序中的变动就可以很好地管理起来。
AOP实现的三个步骤:
1.代理对象的生成。2.拦截器的使用。3.Aspect编织的实现,实现真正的拦截。
AOP的相关概念
一 Advice通知
Advice(通知)定义在连接点做什么,为切面增强提供接口。在Spring AOP中,它主要描述Spring AOP围绕方法调用而注入的切面行为。
Advice是AOP联盟定义的一个接口。具体的接口定义在org.aopalliance.aop;
package org.aopalliance.aop;
public interface Advice {
}
在Spring AOP的实现中,使用了这个统一的接口,并通过这个接口为AOP切面增强的织入功能做了更多的扩展。比如提供了更具体的通
织类型,比如BeforeAdvice,AfterAdvice,ThrowsAdvice等。
在BeforeAdvice继承关系中,BeforeAdvice继承了Advice,MethodBeforeAdvice继承了BeforeAdvice,MethodBeforeAdvice接口定义了
为待增强的目标方法设置的前置增强。
package org.springframework.aop;
import java.lang.reflect.Method;
public interface MethodBeforeAdvice extends BeforeAdvice {
/*
*Method对象:目标方法的反射对象;Object[]对象数组,这个对象中包含目标方法的输入参数。
*/
void before(Method method, Object[] args, Object target) throws Throwable;
}
作为回调函数,before函数的实现在Advic中被配置到目标方法后,会在调用目标方法时被调用。
在AfterAdvice的继承关系中,有一系列对AfterReturing的实现和扩展,比如AfterReturningAdvice就是其中比较常用的一个。
package org.springframework.aop;
import java.lang.reflect.Method;
public interface AfterReturningAdvice extends AfterAdvice {
void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable;
}
afterReturning方法也是一个回调函数,AOP应用需要在这个接口实现中提供切面增强的具体设计,在这个Advice通知被正确配置以后,在目标方法调用
结束并成功返回的时候,接口会被Spring AOP回调。
还有一种通知是ThrowAdvice,并没有指定需要实现的接口方法,它在抛出异常时被回调,这个回调是AOP使用反射机制来完成的。
public interface ThrowsAdvice extends AfterAdvice {
}
二 PointCut切点
PointCut(切点)决定Advice通知应该作用于哪个连接点,也就是说通过PiontCut切点来定义需要增强的方法的集合。
在PointCut基本接口定义源码:
public interface Pointcut {
ClassFilter getClassFilter();
MethodMatcher getMethodMatcher();
Pointcut TRUE = TruePointcut.INSTANCE;
}
在接口定义中需要返回一个MethodMatcher。PointCut的匹配判断功能,具体是由这个返回的MethodMatcher来完成,也就是说由MethodMatcher来
判断是否需要对当前方法调用增强功能,或者是否需要对当前调用方法应用配置好的Advice通知。
package org.springframework.aop;
import java.lang.reflect.Method;
public interface MethodMatcher {
boolean matches(Method method, Class<?> targetClass);
boolean isRuntime();
boolean matches(Method method, Class<?> targetClass, Object[] args);
MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
}
以JdkRegexpMethodPointcut的实现原理为例,来了解PointCut的工作原理。JdkRegexpMethodPointcut完成通过正则表达式来对方法名进行匹配。其继承关系如下
StaticmethodMatcher继承MethodMatcher,JdkRegexpMethodPointcut继承StaticmethodMatcher。
public abstract class StaticMethodMatcher implements MethodMatcher {
@Override
public final boolean isRuntime() {
return false;
}
@Override
public final boolean matches(Method method, Class<?> targetClass, Object[] args) {
// should never be invoked because isRuntime() returns false
throw new UnsupportedOperationException("Illegal MethodMatcher usage");
}
}
public class JdkRegexpMethodPointcut extends AbstractRegexpMethodPointcut {
private Pattern[] compiledPatterns = new Pattern[0];
private Pattern[] compiledExclusionPatterns = new Pattern[0];
@Override
protected void initPatternRepresentation(String[] patterns) throws PatternSyntaxException {
this.compiledPatterns = compilePatterns(patterns);
}
@Override
protected void initExcludedPatternRepresentation(String[] excludedPatterns) throws PatternSyntaxException {
this.compiledExclusionPatterns = compilePatterns(excludedPatterns);
}
@Override
protected boolean matches(String pattern, int patternIndex) {
Matcher matcher = this.compiledPatterns[patternIndex].matcher(pattern);
return matcher.matches();
}
//这个matcher方法就是使用正则表达式对方法名进行匹配的地方
@Override
protected boolean matchesExclusion(String candidate, int patternIndex) {
Matcher matcher = this.compiledExclusionPatterns[patternIndex].matcher(candidate);
return matcher.matches();
}
private Pattern[] compilePatterns(String[] source) throws PatternSyntaxException {
Pattern[] destination = new Pattern[source.length];
for (int i = 0; i < source.length; i++) {
destination[i] = Pattern.compile(source[i]);
}
return destination;
}
}
其实AOP框架中对matches方法的调用,是在JdkDynamicAopProxy的invoke方法中触发的。这个在以后的分析进行叙述。
三 Advisor通知器
完成对目标方法的切面增强设计(Advice)和关注点的设计(Pointcut)以后,需要一个对象将它们结合起来,完成这个作用的就是Advisor(通知器)。通过Advisor,可以定义应该使用哪个通知并在哪个关注点使用它,也就是通过Advisor,把Advisor和Pointcut结合起来,这个结合为IoC容器配置AOP应用提供了便利。
以一个Advisor的实例(DefaultPointcutAdvisor)来了解Advisor的工作原理。
package org.springframework.aop.support;
import java.io.Serializable;
import org.aopalliance.aop.Advice;
import org.springframework.aop.Pointcut;
public class DefaultPointcutAdvisor extends AbstractGenericPointcutAdvisor implements Serializable {
private Pointcut pointcut = Pointcut.TRUE;
//DefaultPointcutAdvisor有两个属性,pointcut和advice,其中advice定义在其父类AbstractGenericPointcutAdvisor中
public DefaultPointcutAdvisor() {
}
public DefaultPointcutAdvisor(Advice advice) {
this(Pointcut.TRUE, advice);
}
public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) {
this.pointcut = pointcut;
setAdvice(advice);
}
public void setPointcut(Pointcut pointcut) {
this.pointcut = (pointcut != null ? pointcut : Pointcut.TRUE);
}
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
@Override
public String toString() {
return getClass().getName() + ": pointcut [" + getPointcut() + "]; advice [" + getAdvice() + "]";
}
}