搞懂AOP之一,拦截器链

写在前面

本篇不准备对着源码一步一步讲解这一过程,而是准备先剖析一下这一过程中所用到的一些类和方法的功能,当这些“螺丝”都熟悉之后,再一步一步看源码的时候,便会畅通无阻。这也是我在阅读源码过程中的感觉,因为spring的整套源码一环套一环,流程很长,可能跟着跟着就不知所云了。但是如果我们分解一长串流程,一步一步去拆解,最后串联起来的那一刻就会恍然大悟。

相关知识

AOP代理增强时机

bean的创建过程中的初始化阶段的后置处理(postProcessAfterInitialization),在满足条件的情况下会对bean进行AOP增强。核心实现就是AbstractAutoProxyCreator的wrapIfNecessary方法。该方法主要逻辑实现就是,找到容器中能够应用到当前所创建的bean的切面,利用切面为bean创建代理对象。

AOP的一些概念

在真正介绍拦截器链之前,先理清一下一些我自己第一次看源码时比较模糊的概念。
切面:对主业务逻辑的一种增强。spring中的Advice和Advisor都是切面的一种实现,只不过Advisor相比Advice能够实现更复杂的逻辑。
织入:将切面应用到目标方法或类的过程。比如cglib的intercept方法,jdk代理的invoke方法,其完成的逻辑都可以叫做织入。
连接点:可以被切面织入的方法。
切点:具体被切面织入的方法。
连接点和切点什么区别呢?一个修饰词是“可以”,一个修饰词是“具体”。在我看来,切点规定了哪些方法将被切面增强,满足切点的限定条件都将得到增强。而连接点表示了满足切点扫描的方法的集合,这些方法可能有些满足切点的限定条件,有些不满足。
来看一下spring中对切点的定义是什么:

public interface Pointcut {
   
	/**
	 * Return the ClassFilter for this pointcut.
	 * @return the ClassFilter (never {@code null})
	 */
	ClassFilter getClassFilter();
	/**
	 * Return the MethodMatcher for this pointcut.
	 * @return the MethodMatcher (never {@code null})
	 */
	MethodMatcher getMethodMatcher();
	/**
	 * Canonical Pointcut instance that always matches.
	 */
	Pointcut TRUE = TruePointcut.INSTANCE;
}

其中的ClassFilter和MethodMatcher都具有matches方法,决定了哪些类或方法满足切点的限定条件。
把这些概念串起来,我总结就是:

spring的AOP就是把切面(Advice、Advisor)织入(Weaving)到满足切点(PointCut)限定条件的连接点(JoinPoint)的过程。

AOP拦截链

下面开始正菜了,在spring中,我们怎么用切面去增强一个类呢?是拦截!我们拦截方法的执行,去添加一些额外的逻辑。那如何进行拦截呢?当然是动态代理了。

在spring的整个生态中,强依赖动态代理,所以,最最基础的cglib代理和jdk代理是我们学习spring的必备基础。spring有多强依赖动态代理呢,对于cglib代理来说,spring直接copy了一份cglib代理的源码到自己的框架中。以至于你去搜MethodInterceptor会发现有两个相同的类,一个是在net.sf.cglib.proxy包下,一个是在org.springframework.cglib.proxy包下。

spring是如何对方法进行拦截呢?答案是通过MethodInterceptor。

public interface MethodInterceptor extends Interceptor {
   

	/**
	 * Implement this method to perform extra treatments before and
	 * after the invocation. Polite implementations would certainly
	 * like to invoke {@link Joinpoint#proceed()}.
	 * @param invocation the method invocation joinpoint
	 * @return the result of the call to {@link Joinpoint#proceed()};
	 * might be intercepted by the interceptor
	 * @throws Throwable if the interceptors or the target object
	 * throws an exception
	 */
	Object invoke(MethodInvocation invocation) throws Throwable;

}

也就是说,被增强类的方法执行时,实际是通过MethodInterceptor#invoke被调用的。

需要注意的是,用于AOP拦截的MethodInterceptor与cglib代理增强的MethodInterceptor虽然类名相同,但是却是完全不同的两个类。这里可以过度解读一下spring的命名(spring的命名是一种艺术)。cglib代理依靠MethodInterceptor#intercept方法实现,jdk代理依靠InvocationHandler#invoke方法实现。而spring AOP实现拦截是依靠MethodInterceptor#invoke方法。注意到没有,这是综合了cglib代理的类名和jdk代理的方法名。

现在我们新建两个拦截器,LogInterceptor和TimeInterceptor,分别用于记录日志和计时。
LogInterceptor

public class LogInterceptor implements MethodInterceptor {
   
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
   
        System.out.println("开始执行");
        Object retVal = invocation.proceed();
        System.out.println("执行完毕");
        return retVal;
    }
}

TimeInterceptor

public class TimeInterceptor implements MethodInterceptor {
   
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
   
        long start = System.currentTimeMillis();
        System.out.println("计时开始");
        Object retVal = invocation.proceed();
        System.out.println("计时结束,耗时:" + (System.currentTimeMillis() - start) / 1000);
        return retVal;
    }
}

同时我们再新建两个spring自己提供的切面Advice,分别是MethodBeforeAdvice和AfterReturningAdvice。
AOPAfterReturningAdvice

public class AOPAfterReturningAdvice implements AfterReturningAdvice {
   
    @Override
    public 
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值