publicclassAopNamespaceHandlerextendsNamespaceHandlerSupport { @Override publicvoidinit() { // In 2.0 XSD as well as in 2.1 XSD. registerBeanDefinitionParser("config", newConfigBeanDefinitionParser()); registerBeanDefinitionParser("aspectj-autoproxy", newAspectJAutoProxyBeanDefinitionParser()); registerBeanDefinitionDecorator("scoped-proxy", newScopedProxyBeanDefinitionDecorator());
// Only in 2.0 XSD: moved to context namespace as of 2.1 registerBeanDefinitionParser("spring-configured", newSpringConfiguredBeanDefinitionParser()); } }
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator // so that it will only instantiate once. MetadataAwareAspectInstanceFactorylazySingletonAspectInstanceFactory= newLazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
// If it's a per target aspect, emit the dummy instantiating aspect. if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) { AdvisorinstantiationAdvisor=newSyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory); advisors.add(0, instantiationAdvisor); }
// 引介的增强器 for (Field field : aspectClass.getDeclaredFields()) { Advisoradvisor= getDeclareParentsAdvisor(field); if (advisor != null) { advisors.add(advisor); } }
if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) { // Static part of the pointcut is a lazy type. PointcutpreInstantiationPointcut= Pointcuts.union( aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
// Make it dynamic: must mutate from pre-instantiation to post-instantiation state. // If it's not a dynamic pointcut, it may be optimized out // by the Spring AOP infrastructure after the first evaluation. this.pointcut = newPerTargetInstantiationModelPointcut( this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory); this.lazy = true; }else { // A singleton aspect. this.pointcut = this.declaredPointcut; this.lazy = false; this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut); } } private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) { Adviceadvice=this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut, this.aspectInstanceFactory, this.declarationOrder, this.aspectName); return (advice != null ? advice : EMPTY_ADVICE); }
// If we get here, we know we have an AspectJ method. // Check that it's an AspectJ-annotated class if (!isAspect(candidateAspectClass)) { thrownewAopConfigException("Advice must be declared inside an aspect type: " + "Offending method '" + candidateAdviceMethod + "' in class [" + candidateAspectClass.getName() + "]"); }
if (logger.isDebugEnabled()) { logger.debug("Found AspectJ method: " + candidateAdviceMethod); }
AbstractAspectJAdvice springAdvice;
switch (aspectJAnnotation.getAnnotationType()) { case AtPointcut: if (logger.isDebugEnabled()) { logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'"); } returnnull; case AtAround: springAdvice = newAspectJAroundAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtBefore: springAdvice = newAspectJMethodBeforeAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtAfter: springAdvice = newAspectJAfterAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtAfterReturning: springAdvice = newAspectJAfterReturningAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); AfterReturningafterReturningAnnotation= (AfterReturning) aspectJAnnotation.getAnnotation(); if (StringUtils.hasText(afterReturningAnnotation.returning())) { springAdvice.setReturningName(afterReturningAnnotation.returning()); } break; case AtAfterThrowing: springAdvice = newAspectJAfterThrowingAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); AfterThrowingafterThrowingAnnotation= (AfterThrowing) aspectJAnnotation.getAnnotation(); if (StringUtils.hasText(afterThrowingAnnotation.throwing())) { springAdvice.setThrowingName(afterThrowingAnnotation.throwing()); } break; default: thrownewUnsupportedOperationException( "Unsupported advice type on method: " + candidateAdviceMethod); }
// Now to configure the advice... springAdvice.setAspectName(aspectName); springAdvice.setDeclarationOrder(declarationOrder); String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod); if (argNames != null) { springAdvice.setArgumentNamesFromStringArray(argNames); } springAdvice.calculateArgumentBindings();
publicstaticbooleancanApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) { if (advisor instanceof IntroductionAdvisor) { return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass); }elseif (advisor instanceof PointcutAdvisor) { PointcutAdvisorpca= (PointcutAdvisor) advisor; return canApply(pca.getPointcut(), targetClass, hasIntroductions); }else { // It doesn't have a pointcut so we assume it applies. returntrue; } }
publicstaticbooleancanApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) { Assert.notNull(pc, "Pointcut must not be null"); if (!pc.getClassFilter().matches(targetClass)) { // 先匹配类型 returnfalse; }
MethodMatchermethodMatcher= pc.getMethodMatcher(); if (methodMatcher == MethodMatcher.TRUE) { // No need to iterate the methods if we're matching any method anyway... returntrue; }
// Massage return value if necessary. Class<?> returnType = method.getReturnType(); if (retVal != null && retVal == target && returnType != Object.class && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { // Special case: it returned "this" and the return type of the method // is type-compatible. Note that we can't help if the target sets // a reference to itself in another returned object. retVal = proxy; }elseif (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) { thrownewAopInvocationException( "Null return value from advice does not match primitive return type for: " + method); } return retVal; }finally { if (target != null && !targetSource.isStatic()) { // Must have come from TargetSource. targetSource.releaseTarget(target); } if (setProxyContext) { // Restore old proxy. AopContext.setCurrentProxy(oldProxy); } } }
public Object proceed()throws Throwable { // We start with an index of -1 and increment early. if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); // 执行完所有增强器后执行目标方法 }
public Object getProxy(@Nullable ClassLoader classLoader) { if (logger.isTraceEnabled()) { logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource()); }
try { Class<?> rootClass = this.advised.getTargetClass(); Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
Callback[] callbacks = getCallbacks(rootClass); 设置拦截器 Class<?>[] types = newClass<?>[callbacks.length]; for (intx=0; x < types.length; x++) { types[x] = callbacks[x].getClass(); } // fixedInterceptorMap only populated at this point, after getCallbacks call above enhancer.setCallbackFilter(newProxyCallbackFilter( this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset)); enhancer.setCallbackTypes(types);
// Generate the proxy class and create a proxy instance. return createProxyClassAndInstance(enhancer, callbacks); }catch (CodeGenerationException | IllegalArgumentException ex) { thrownewAopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() + ": Common causes of this problem include using a final class or a non-visible class", ex); }catch (Throwable ex) { // TargetSource.getTarget() failed thrownewAopConfigException("Unexpected AOP exception", ex); } }
// Choose a "straight to target" interceptor. (used for calls that are // unadvised but can return this). May be required to expose the proxy. Callback targetInterceptor; if (exposeProxy) { targetInterceptor = (isStatic ? newStaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) : newDynamicUnadvisedExposedInterceptor(this.advised.getTargetSource())); }else { targetInterceptor = (isStatic ? newStaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) : newDynamicUnadvisedInterceptor(this.advised.getTargetSource())); }
// Choose a "direct to target" dispatcher (used for // unadvised calls to static targets that cannot return this). CallbacktargetDispatcher= (isStatic ? newStaticDispatcher(this.advised.getTargetSource().getTarget()) : newSerializableNoOp());
Callback[] mainCallbacks = newCallback[] { aopInterceptor, // for normal advice targetInterceptor, // invoke target without considering advice, if optimized newSerializableNoOp(), // no override for methods mapped to this targetDispatcher, this.advisedDispatcher, newEqualsInterceptor(this.advised), newHashCodeInterceptor(this.advised) };
Callback[] callbacks;
// If the target is a static one and the advice chain is frozen, // then we can make some optimizations by sending the AOP calls // direct to the target using the fixed chain for that method. if (isStatic && isFrozen) { Method[] methods = rootClass.getMethods(); Callback[] fixedCallbacks = newCallback[methods.length]; this.fixedInterceptorMap = newHashMap<>(methods.length);
// TODO: small memory optimization here (can skip creation for methods with no advice) for (intx=0; x < methods.length; x++) { List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass); fixedCallbacks[x] = newFixedChainStaticTargetInterceptor( chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass()); this.fixedInterceptorMap.put(methods[x].toString(), x); }
// Now copy both the callbacks from mainCallbacks // and fixedCallbacks into the callbacks array. callbacks = newCallback[mainCallbacks.length + fixedCallbacks.length]; System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length); System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length); this.fixedInterceptorOffset = mainCallbacks.length; }else { callbacks = mainCallbacks; } return callbacks; }