Spring深度解析-11、AOP概念

什么是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很简单,作为通知器,他的作用就是把通知与切面联系起来。

发布了80 篇原创文章 · 获赞 12 · 访问量 2万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览