Spring Aop的实现

最近几天看了Spring aop部分的源码,刚开始是看书的,那本业界还挺有名气的Spring技术内幕,但是看了好久也没看出个大概来,还总是忘。昨天决定用eclipse调试的功能来跟踪源码。到现在为止,脉络已经算比较清楚了。现总结如下:

先看几个名词术语

1.pointcut:切点,目标方法的范围,就是说那些方法需要被增强

2.advice:通知,具体需要增强的方法,就是说需要为目标方法怎么增强

3.joinpoint:目标方法,执行目标对象的方法

其他名词不需要过多解释


其实这个过程大致分为以下几步:

1.生成代理对象,需要清楚,增强方法的执行都是代理对象在执行的,这样就与目标对象解耦开来,具体怎么生成代理对象,无外乎动态代理和cglib两种方式。

2.生成代理对象之后,当目标方法被执行的时候,JdkDynamicAopProxy的invoke()方法就被执行,因为这个类实现了InvocationHandler接口,所以当目标对象的所有方法被调用的时候都会在invoke()方法里面被拦截。拦截后怎么做呢?针对每个方法,生成拦截器!具体是怎么生成的呢?经过跟踪源码,发现,每个方法都会生成针对于这个方法的拦截器。当然,步骤是,先读取配置中的所有Advisor,遍历每个Advisor,如果匹配当前方法,则将这个Advisor封装为拦截器添加到当前方法的拦截器链中,然后,依次执行这个拦截器链。这个拦截器链是ReflectiveMethodInvocation这个类调用的,调用方法为proceed(),在这个方法中,依次遍历每个拦截器,在拦截器中回调proceed()方法,又用到了回调!!!当拦截器执行完后,调用目标对象的方法。好了,那么是如何将advice织入的呢?在拦截器的invoke()方法中,比如是前置通知,则先执行通知,再调用proceed()方法,类似的。。。最终,实现了通知的织入。


补充:

其实这个拦截器和struts2的拦截器机制是相同的,struts2是通过actionInvocation里面调用拦截器的invoke()方法的,而拦截器的invoke()方法里面继续回调invocation()里面的intercept()方法的

补充2:重新跟踪了一遍源码:Spring的Aop机制是这样的:首先,会在配置文件中配置拦截器,可以配置多个拦截器,也可以不配置拦截器,spring会为每个真实对象都生成一个代理对象,所以当执行目标方法时,会自动被代理对象的invoke()方法所拦截。进入invoke方法的执行流程中,这里截取部分代码

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		MethodInvocation invocation = null;
		Object oldProxy = null;
		boolean setProxyContext = false;

		TargetSource targetSource = this.advised.targetSource;
		Class targetClass = null;
		Object target = null;

		try {
			if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
				// The target does not implement the equals(Object) method itself.
				return (equals(args[0]) ? Boolean.TRUE : Boolean.FALSE);
			}
			if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
				// The target does not implement the hashCode() method itself.
				return new Integer(hashCode());
			}
			if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
					method.getDeclaringClass().isAssignableFrom(Advised.class)) {
				// Service invocations on ProxyConfig with the proxy config...
				return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
			}

			Object retVal = null;

			if (this.advised.exposeProxy) {
				// Make invocation available if necessary.
				oldProxy = AopContext.setCurrentProxy(proxy);
				setProxyContext = true;
			}

			// May be <code>null</code>. Get as late as possible to minimize the time we "own" the target,
			// in case it comes from a pool.
			target = targetSource.getTarget();
			if (target != null) {
				targetClass = target.getClass();
			}

			// Get the interception chain for this method.
			List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);//这里是获取拦截器链的过程,也就是获取
                     //配置文件中的拦截器的过程,在这个过程中,会将文件中的拦截器一个个加入到链中,并已经封装了通知类型,这个顺序应该是根据配置文件中的
                   //配置顺序加入的,但是,后置通知好像是反着加入的!!因为后置通知的执行顺序是反的,这样可以刚好按照配置顺序执行

			// Check whether we have any advice. If we don't, we can fallback on direct
			// reflective invocation of the target, and avoid creating a MethodInvocation.
			if (chain.isEmpty()) {
				// We can skip creating a MethodInvocation: just invoke the target directly
				// Note that the final invoker must be an InvokerInterceptor so we know it does
				// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
			}
			else {
				// We need to create a method invocation...
				invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				// Proceed to the joinpoint through the interceptor chain.
				retVal = invocation.proceed();//这是个重点,不断的回调拦截器链来执行增强方法
			}
看下面proceed()方法的执行:

public Object proceed() throws Throwable {
		//	We start with an index of -1 and increment early.
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			return invokeJoinpoint();//当前拦截器为空时,执行目标方法,即是Joinpoint()方法
		}

		Object interceptorOrInterceptionAdvice =
		    this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			// Evaluate dynamic method matcher here: static part will already have
			// been evaluated and found to match.
			InterceptorAndDynamicMethodMatcher dm =
			    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
			if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
				return dm.interceptor.invoke(this);
			}
			else {
				// Dynamic matching failed.
				// Skip this interceptor and invoke the next in the chain.
				return proceed();
			}
		}
		else {
			// It's an interceptor, so we just invoke it: The pointcut will have
			// been evaluated statically before this object was constructed.
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);//可以认为跳到这个方法,就是执行具体拦截器的方法
		}
	}
第一个执行的拦截器是ExposeInvocationInterceptor,其实里面就是继续回调

public Object invoke(MethodInvocation mi) throws Throwable {
		Object old = invocation.get();
		invocation.set(mi);
		try {
			return mi.proceed();
		}
		finally {
			invocation.set(old);
		}
	}
如果是个前置通知,代码是这样的:

public Object invoke(MethodInvocation mi) throws Throwable {
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );//这个就是执行的核心方法,先执行前置方法,然后继续回调!
		return mi.proceed();
	}

如果是个后置通知,代码是这样的:

public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			return mi.proceed();//先继续回调,
		}
		finally {
			invokeAdviceMethod(getJoinPointMatch(), null, null);//最终执行后置通知,注意,最终执行的顺序是反向的,类似于栈,不断的回调递归,
                                                             //所以,后置通知执行顺序相反,但是假如拦截器链顺序如果反向,结果还是顺序执行
		}
	}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值