Spring源码学习篇4 - XML配置了解AOP

从一个简单的列子来看XML配置AOP

<bean id="TargetObject" class="aoptest.TargetObject"/>

<bean id="AspectHandler" class="aoptest.AspectHandler"/>

<aop:config>
    <aop:aspect ref="AspectHandler">

        <aop:pointcut id="testPointcutId"
                      expression="execution(* aoptest.TargetObject.*(String))"/>

        <aop:around pointcut-ref="testPointcutId" method="aroundTest"/>
        <aop:after-returning pointcut-ref="testPointcutId" method="afterReturnTest" returning="param"/>
        <aop:after-throwing pointcut-ref="testPointcutId" method="afterThrowTest" throwing="ex"/>
    </aop:aspect>
</aop:config>

先来看下最终包含的Bean:

 ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("aop_config_test.xml");
 System.out.println(Arrays.toString(ctx.getBeanDefinitionNames()));
 for (String beanDefinitionName : ctx.getBeanDefinitionNames()) {
     Object bean = ctx.getBean(beanDefinitionName);
     System.out.println(String.format("%s --> %s", beanDefinitionName, bean.getClass()));
 }

输出:

TargetObject --> class aoptest.TargetObject$$EnhancerBySpringCGLIB$$f8dc7b35
AspectHandler --> class aoptest.AspectHandler
org.springframework.aop.config.internalAutoProxyCreator --> class org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator
org.springframework.aop.aspectj.AspectJPointcutAdvisor#0 --> class org.springframework.aop.aspectj.AspectJPointcutAdvisor
org.springframework.aop.aspectj.AspectJPointcutAdvisor#1 --> class org.springframework.aop.aspectj.AspectJPointcutAdvisor
org.springframework.aop.aspectj.AspectJPointcutAdvisor#2 --> class org.springframework.aop.aspectj.AspectJPointcutAdvisor
testPointcutId --> class org.springframework.aop.aspectj.AspectJExpressionPointcut

可以看出所有的pointcut、advice全都实例化为独立的bean了;另外,是TargetObject 对应的bean的类型是cglib的代理类;AspectJAwareAdvisorAutoProxyCreator是BeanPostProcessor的一种实现,用来对原有bean创建代理,它是对<aop:config>解析时创建的:

//org.springframework.aop.config.ConfigBeanDefinitionParser#parse
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
	CompositeComponentDefinition compositeDef =
			new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
	parserContext.pushContainingComponent(compositeDef);
	// 这里注册的AspectJAwareAdvisorAutoProxyCreator
	configureAutoProxyCreator(parserContext, element);

	List<Element> childElts = DomUtils.getChildElements(element);
	for (Element elt: childElts) {
		String localName = parserContext.getDelegate().getLocalName(elt);
		if (POINTCUT.equals(localName)) {
			parsePointcut(elt, parserContext);
		}
		else if (ADVISOR.equals(localName)) {
			parseAdvisor(elt, parserContext);
		}
		else if (ASPECT.equals(localName)) {
			parseAspect(elt, parserContext);
		}
	}

	parserContext.popAndRegisterContainingComponent();
	return null;
}

AOP配置的解析

从上面的代码也可以看到,对<aop:config>几个子元素的处理,这里按例子继续看ASPECT的处理。
<aop:aspect>主要有三类子元素pointcut、advice、declare-parents:

  • PointCut
    PointCut创建的Bean是prototype的
//org.springframework.aop.config.ConfigBeanDefinitionParser#createPointcutDefinition
protected AbstractBeanDefinition createPointcutDefinition(String expression) {
	RootBeanDefinition beanDefinition = new RootBeanDefinition(AspectJExpressionPointcut.class);
	beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
	beanDefinition.setSynthetic(true);
	beanDefinition.getPropertyValues().add(EXPRESSION, expression);
	return beanDefinition;
}
  • Advice

/**
 * Parses one of '{@code before}', '{@code after}', '{@code after-returning}',
 * '{@code after-throwing}' or '{@code around}' and registers the resulting
 * BeanDefinition with the supplied BeanDefinitionRegistry.
 * @return the generated advice RootBeanDefinition
 */
private AbstractBeanDefinition parseAdvice(
		String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext,
		List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {

	try {
		this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement)));

		// create the method factory bean
		RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
		methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
		methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
		methodDefinition.setSynthetic(true);

		// create instance factory definition
		RootBeanDefinition aspectFactoryDef =
				new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
		aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
		aspectFactoryDef.setSynthetic(true);

		// register the pointcut
		AbstractBeanDefinition adviceDef = createAdviceDefinition(
				adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
				beanDefinitions, beanReferences);

		// configure the advisor
		RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
		advisorDefinition.setSource(parserContext.extractSource(adviceElement));
		advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
		if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
			advisorDefinition.getPropertyValues().add(
					ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
		}

		// register the final advisor
		parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);

		return advisorDefinition;
	}
	finally {
		this.parseState.pop();
	}
}  
  • declare-parents
private AbstractBeanDefinition parseDeclareParents(Element declareParentsElement, ParserContext parserContext) {
	BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(DeclareParentsAdvisor.class);
	builder.addConstructorArgValue(declareParentsElement.getAttribute(IMPLEMENT_INTERFACE));
	builder.addConstructorArgValue(declareParentsElement.getAttribute(TYPE_PATTERN));

	String defaultImpl = declareParentsElement.getAttribute(DEFAULT_IMPL);
	String delegateRef = declareParentsElement.getAttribute(DELEGATE_REF);

	if (StringUtils.hasText(defaultImpl) && !StringUtils.hasText(delegateRef)) {
		builder.addConstructorArgValue(defaultImpl);
	}
	else if (StringUtils.hasText(delegateRef) && !StringUtils.hasText(defaultImpl)) {
		builder.addConstructorArgReference(delegateRef);
	}
	else {
		parserContext.getReaderContext().error(
				"Exactly one of the " + DEFAULT_IMPL + " or " + DELEGATE_REF + " attributes must be specified",
				declareParentsElement, this.parseState.snapshot());
	}

	AbstractBeanDefinition definition = builder.getBeanDefinition();
	definition.setSource(parserContext.extractSource(declareParentsElement));
	parserContext.getReaderContext().registerWithGeneratedName(definition);
	return definition;
}

代理对象的创建

首先,在开始创建用户的bean之前,BeanPostProcessor会优先实例化,所以AspectJAwareAdvisorAutoProxyCreator 的实例化在其他bean之前。

创建Bean时,比如例子中的TargetObject, org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization 会将TargetObject的实例进行处理,然后返回代理类。

这里有两个关键的步骤,先是找到对应的Advisor,然后根据创建代理:

// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
	this.advisedBeans.put(cacheKey, Boolean.TRUE);
	Object proxy = createProxy(
			bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
	this.proxyTypes.put(cacheKey, proxy.getClass());
	return proxy;
}
匹配Advicor

匹配逻辑主要在org.springframework.aop.support.AopUtils#findAdvisorsThatCanApply中,是对所有的Advisor进行遍历,看与目标类型是否匹配。

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
	if (candidateAdvisors.isEmpty()) {
		return candidateAdvisors;
	}
	List<Advisor> eligibleAdvisors = new ArrayList<>();
	for (Advisor candidate : candidateAdvisors) {
		if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
			eligibleAdvisors.add(candidate);
		}
	}
	boolean hasIntroductions = !eligibleAdvisors.isEmpty();
	for (Advisor candidate : candidateAdvisors) {
		if (candidate instanceof IntroductionAdvisor) {
			// already processed
			continue;
		}
		if (canApply(candidate, clazz, hasIntroductions)) {
			eligibleAdvisors.add(candidate);
		}
	}
	return eligibleAdvisors;
}

每个Advisor 的匹配逻辑如下:

public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
	if (advisor instanceof IntroductionAdvisor) {
		return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
	}
	else if (advisor instanceof PointcutAdvisor) {
		PointcutAdvisor pca = (PointcutAdvisor) advisor;
		return canApply(pca.getPointcut(), targetClass, hasIntroductions);
	}
	else {
		// It doesn't have a pointcut so we assume it applies.
		return true;
	}
}

可以看到有三个分支IntroductionAdvisor、PointcutAdvisor、没有pointcut。
例子中配置的Advisor全是PointcutAdvisor的类型,先看下它是如何匹配的:

对于Advicor的Pointcut 是否匹配一个类,会遍历类以及它的接口的所有方法,找到一个匹配的就认为匹配。方法匹配的时候需要匹配两个部分:

  • PointCut是否匹配
  • adviceMethod是否匹配
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
	Assert.notNull(pc, "Pointcut must not be null");
	if (!pc.getClassFilter().matches(targetClass)) {
		return false;
	}

	MethodMatcher methodMatcher = pc.getMethodMatcher();
	if (methodMatcher == MethodMatcher.TRUE) {
		// No need to iterate the methods if we're matching any method anyway...
		return true;
	}

	IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
	if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
		introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
	}

	Set<Class<?>> classes = new LinkedHashSet<>();
	if (!Proxy.isProxyClass(targetClass)) {
		classes.add(ClassUtils.getUserClass(targetClass));
	}
	classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

	for (Class<?> clazz : classes) {
		Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
		for (Method method : methods) {
			if (introductionAwareMethodMatcher != null ?
					introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
					methodMatcher.matches(method, targetClass)) {
				return true;
			}
		}
	}

	return false;
}

方法签名的匹配相有很多细节,比如参数、方法名称、返回值等等,参见org.aspectj.weaver.patterns.SignaturePattern#matchesExactlyMethod

	private FuzzyBoolean matchesExactlyMethod(JoinPointSignature aMethod, World world, boolean subjectMatch) {
		if (parametersCannotMatch(aMethod)) {
			// System.err.println("Parameter types pattern " + parameterTypes + " pcount: " + aMethod.getParameterTypes().length);
			return FuzzyBoolean.NO;
		}
		// OPTIMIZE only for exact match do the pattern match now? Otherwise defer it until other fast checks complete?
		if (!name.matches(aMethod.getName())) {
			return FuzzyBoolean.NO;
		}
		// Check the throws pattern
		if (subjectMatch && !throwsPattern.matches(aMethod.getExceptions(), world)) {
			return FuzzyBoolean.NO;
		}

		// '*' trivially matches everything, no need to check further
		if (!declaringType.isStar()) {
			if (!declaringType.matchesStatically(aMethod.getDeclaringType().resolve(world))) {
				return FuzzyBoolean.MAYBE;
			}
		}

		// '*' would match any return value
		if (!returnType.isStar()) {
			boolean b = returnType.isBangVoid();
			if (b) {
				String s = aMethod.getReturnType().getSignature();
				if (s.length() == 1 && s.charAt(0) == 'V') {
					// it is void, so not a match
					return FuzzyBoolean.NO;
				}
			} else {
				if (returnType.isVoid()) {
					String s = aMethod.getReturnType().getSignature();
					if (s.length() != 1 || s.charAt(0) != 'V') {
						// it is not void, so not a match
						return FuzzyBoolean.NO;
					}
				} else {
					if (!returnType.matchesStatically(aMethod.getReturnType().resolve(world))) {
						// looking bad, but there might be parameterization to consider...
						if (!returnType.matchesStatically(aMethod.getGenericReturnType().resolve(world))) {
							// ok, it's bad.
							return FuzzyBoolean.MAYBE;
						}
					}
				}
			}
		}

		// The most simple case: pattern is (..) will match anything
		if (parameterTypes.size() == 1 && parameterTypes.get(0).isEllipsis()) {
			return FuzzyBoolean.YES;
		}

		if (!parameterTypes.canMatchSignatureWithNParameters(aMethod.getParameterTypes().length)) {
			return FuzzyBoolean.NO;
		}

		// OPTIMIZE both resolution of these types and their annotations should be deferred - just pass down a world and do it lower
		// down
		// ResolvedType[] resolvedParameters = world.resolve(aMethod.getParameterTypes());

		ResolvableTypeList rtl = new ResolvableTypeList(world, aMethod.getParameterTypes());
		// Only fetch the parameter annotations if the pointcut is going to be matching on them
		ResolvedType[][] parameterAnnotationTypes = null;
		if (isMatchingParameterAnnotations()) {
			parameterAnnotationTypes = aMethod.getParameterAnnotationTypes();
			if (parameterAnnotationTypes != null && parameterAnnotationTypes.length == 0) {
				parameterAnnotationTypes = null;
			}
		}

		if (!parameterTypes.matches(rtl, TypePattern.STATIC, parameterAnnotationTypes).alwaysTrue()) {
			// It could still be a match based on the generic sig parameter types of a parameterized type
			if (!parameterTypes.matches(new ResolvableTypeList(world, aMethod.getGenericParameterTypes()), TypePattern.STATIC,
					parameterAnnotationTypes).alwaysTrue()) {
				return FuzzyBoolean.MAYBE;
				// It could STILL be a match based on the erasure of the parameter types??
				// to be determined via test cases...
			}
		}

		// check that varargs specifications match
		if (!matchesVarArgs(aMethod, world)) {
			return FuzzyBoolean.MAYBE;
		}

		// passed all the guards..
		return FuzzyBoolean.YES;
	}
创建代理对象

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy

创建代理主要有两种方式:JdkDynamicAopProxy、ObjenesisCglibAopProxy

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
	if (!NativeDetector.inNativeImage() &&
			(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
		Class<?> targetClass = config.getTargetClass();
		if (targetClass == null) {
			throw new AopConfigException("TargetSource cannot determine target class: " +
					"Either an interface or a target is required for proxy creation.");
		}
		if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
			return new JdkDynamicAopProxy(config);
		}
		return new ObjenesisCglibAopProxy(config);
	}
	else {
		return new JdkDynamicAopProxy(config);
	}
}

JDK动态代理

JDK动态代理比较清楚, 可以看到InvocationHandler就是JdkDynamicAopProxy

org.springframework.aop.framework.JdkDynamicAopProxy#getProxy(java.lang.ClassLoader)
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
	if (logger.isTraceEnabled()) {
		logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
	}
	return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
}

所以,JDK动态代理的Bean相关的方法调用,会先交由org.springframework.aop.framework.JdkDynamicAopProxy#invoke来执行,在invoke中找到对应的Advice并执行,或者执行被代理对象的方法。

// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);

// Get the interception chain for this method.
List<Object> 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.
	Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
	retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
	// We need to create a method invocation...
	MethodInvocation invocation =
			new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
	// Proceed to the joinpoint through the interceptor chain.
	retVal = invocation.proceed();
}
cglib代理

处理类是CglibAopProxy,通过Enhancer创建代理类,代理类相关方法交由Callback的实例来执行。比如可以在org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor#intercept中找到切面相关逻辑:

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
	Object oldProxy = null;
	boolean setProxyContext = false;
	Object target = null;
	TargetSource targetSource = this.advised.getTargetSource();
	try {
		if (this.advised.exposeProxy) {
			// Make invocation available if necessary.
			oldProxy = AopContext.setCurrentProxy(proxy);
			setProxyContext = true;
		}
		// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
		target = targetSource.getTarget();
		Class<?> targetClass = (target != null ? target.getClass() : null);
		List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
		Object retVal;
		// Check whether we only have one InvokerInterceptor: that is,
		// no real advice, but just reflective invocation of the target.
		if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
			// 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.
			Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
			retVal = methodProxy.invoke(target, argsToUse);
		}
		else {
			// We need to create a method invocation...
			retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
		}
		retVal = processReturnType(proxy, target, method, retVal);
		return retVal;
	}
	finally {
		if (target != null && !targetSource.isStatic()) {
			targetSource.releaseTarget(target);
		}
		if (setProxyContext) {
			// Restore old proxy.
			AopContext.setCurrentProxy(oldProxy);
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值