什么是AOP
AOP是Aspect-Oriented Programming(面向方面或者面向切面编程)。
AOP将项目中与具体业务无关的,且各个模块会公用的,用来解决特定领域功能的代码抽离出来成为独立的模块,业务代码只需要专注于自己的业务逻辑,当需要用到相应的功能,只需要在关注的切面织入需要的功能即可。
Advice通知
Advice定义了再连接点做什么,用来描述spring AOP围绕方法调用而注入的切面行为。
Spring AOP提供了多种Advice通知可供开发者选择,其中主要关注五大类型的通知:
前置增强:
BeforeAdvice 在方法执行前执行
后置增强:
AfterReturningAdvice 在方法执行成功并return后执行
环绕增强:
MethodInterceptor 在方法执行前后和抛出异常时执行
抛出异常增强:
ThrowsAdvice 在目标方法抛出异常时执行。
这里通过BeforeAdvice来了解一下Advice。
使用spring的aop来实现前置增强,一般使用BeforeAdvice的子接口MethodBeforeAdvice来实现。
MethodBeforeAdvice:
public interface MethodBeforeAdvice extends BeforeAdvice {
void before(Method var1, Object[] var2, Object var3) throws Throwable;
}
Spring提供了一个案例:CountingBeforeAdvice
用来在目标方法执行前,做计数的操作,从而实现对方法执行次数做统计,
CountingBeforeAdvice 继承MethodCounter[用于方法计数统计],实现MethodBeforeAdvice接口。
public class CountingBeforeAdvice extends MethodCounter implements MethodBeforeAdvice {
@Override
public void before(Method m, Object[] args, Object target) throws Throwable {
count(m);
}
}
public class MethodCounter implements Serializable {
/** Method name --> count, does not understand overloading */
private HashMap<String, Integer> map = new HashMap<>();
private int allCount;
protected void count(Method m) {
count(m.getName());
}
protected void count(String methodName) {
Integer i = map.get(methodName);
i = (i != null) ? new Integer(i.intValue() + 1) : new Integer(1);
map.put(methodName, i);
++allCount;
}
public int getCalls(String methodName) {
Integer i = map.get(methodName);
return (i != null ? i.intValue() : 0);
}
public int getCalls() {
return allCount;
}
/**
* A bit simplistic: just wants the same class.
* Doesn't worry about counts.
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object other) {
return (other != null && other.getClass() == this.getClass());
}
@Override
public int hashCode() {
return getClass().hashCode();
}
}
PointCut切点
PointCut决定了Advice通知应该作用于哪些点,换句话说,PointCut定义了需要增强的方法的集合。
我们先来看下PointCut这个接口定义了什么
public interface Pointcut {
Pointcut TRUE = TruePointcut.INSTANCE;
//类过滤器,定义了需要增强的类的过滤条件
ClassFilter getClassFilter();
//方法匹配器,定义了需要增强的方法的匹配条件
MethodMatcher getMethodMatcher();
}
一般来说,AOP常用在对于方法的增强上。所以MethodMatcher会更常用到。
举例看下PointCut:
JdkRegexpMethodPointcut,这是一个通过正则表达式来匹配方法的切点,实现了PointCut,MethodMatcher,在其父类StaticMethodMatcherPointcut中可以看到,getMethodMatcher返回this,也就是说JdkRegexpMethodPointcut本身也就是他的MethodMatcher,通过JdkRegexpMethodPointcut的matches方法进行方法的匹配,可以看到JdkRegexpMethodPointcut的mathes方法正是正则表达式的匹配。
protected boolean matches(String pattern, int patternIndex) {
Matcher matcher = this.compiledPatterns[patternIndex].matcher(pattern);
return matcher.matches();
}
此外,AOP还提供了其他的MethodPointCut。
比如NameMatchMethodPointCut,通过方法名相等或者匹配来实现Advice的匹配。
public boolean matches(Method method, Class targetClass) {
Iterator i$ = this.mappedNames.iterator();
String mappedName;
do {
if (!i$.hasNext()) {
return false;
}
mappedName = (String)i$.next();
} while(!mappedName.equals(method.getName()) && !this.isMatch(method.getName(), mappedName));
return true;
}
protected boolean isMatch(String methodName, String mappedName) {
return PatternMatchUtils.simpleMatch(mappedName, methodName);
}
Advisor通知器
完成对目标方法的切面增强和关注点的设计以后,需要一个对象把两者结合起来,这个对象就是Advisor通知器,通过Advisor定义应该使用哪个通知,并且在哪个关注点去使用它。
在Spring的AOP中,以DefaultPointcutAdvisor来了解Advisor通知器:
public class DefaultPointcutAdvisor extends AbstractGenericPointcutAdvisor implements Serializable {
private Pointcut pointcut;
public DefaultPointcutAdvisor() {
this.pointcut = Pointcut.TRUE;
}
public DefaultPointcutAdvisor(Advice advice) {
this(Pointcut.TRUE, advice);
}
public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) {
this.pointcut = Pointcut.TRUE;
this.pointcut = pointcut;
this.setAdvice(advice);
}
public void setPointcut(Pointcut pointcut) {
this.pointcut = pointcut != null ? pointcut : Pointcut.TRUE;
}
public Pointcut getPointcut() {
return this.pointcut;
}
public String toString() {
return this.getClass().getName() + ": pointcut [" + this.getPointcut() + "]; advice [" + this.getAdvice() + "]";
}
}
其实Advisor很简单,作为通知器,他的作用就是把通知与切面联系起来。