1. 程式人生 > >spring aop 之增強器處理

spring aop 之增強器處理

spring aop 原始碼分析之增強器獲取

public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
    //獲取標記AspectJ的類
        Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
    //獲取標記Aspect的name   
        String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
        validate(aspectClass);

        // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once. MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory = new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory); List<Advisor> advisors = new LinkedList<>(); //遍歷增強類方法(除了@Pointcut標註的方法)
for (Method method : getAdvisorMethods(aspectClass)) { Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName); if (advisor != null) { advisors.add(advisor); } } // If it's a per target aspect, emit the dummy instantiating aspect.
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) { //如果尋找的增強器不為空而且又配置了增強延遲初始化那麼需要在首位加入同步例項化增強器 Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory); advisors.add(0, instantiationAdvisor); } // 獲取DeclareParents註解 for (Field field : aspectClass.getDeclaredFields()) { Advisor advisor = getDeclareParentsAdvisor(field); if (advisor != null) { advisors.add(advisor); } } return advisors; }

千呼萬喚始出來 這裡最重要的方法來了getAdvisor

public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aif,
            int declarationOrderInAspect, String aspectName) {

        validate(aif.getAspectMetadata().getAspectClass());
//切入點的獲取 
        AspectJExpressionPointcut ajexp =getPointcut(candidateAdviceMethod, aif.getAspectMetadata().getAspectClass());
        if (ajexp == null) {
            return null;
        }
//根據切點資訊生成增強器
        return new InstantiationModelAwarePointcutAdvisorImpl(
                this, ajexp, aif, candidateAdviceMethod, declarationOrderInAspect, aspectName);
    }
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
//獲取方法上的註解
 AspectJAnnotation<?> aspectJAnnotation =AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
        if (aspectJAnnotation == null) {
            return null;
        }
//使用AspectJExpressionPointcut封裝獲取的資訊        
        AspectJExpressionPointcut ajexp =
                new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
        ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
        return ajexp;
    }
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
        Class<?>[] classesToLookFor = new Class<?>[] {
                Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class};
        for (Class<?> c : classesToLookFor) {
            AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) c);
            if (foundAnnotation != null) {
                return foundAnnotation;
            }
        }
        return null;
    }

根據切入點資訊生成增強。

public InstantiationModelAwarePointcutAdvisorImpl(AspectJAdvisorFactory af, AspectJExpressionPointcut ajexp,
            MetadataAwareAspectInstanceFactory aif, Method method, int declarationOrderInAspect, String aspectName) {

        this.declaredPointcut = ajexp;
        this.method = method;
        this.atAspectJAdvisorFactory = af;
        this.aspectInstanceFactory = aif;
        this.declarationOrder = declarationOrderInAspect;
        this.aspectName = aspectName;

        if (aif.getAspectMetadata().isLazilyInstantiated()) {
            // Static part of the pointcut is a lazy type.
            Pointcut preInstantiationPointcut =
                    Pointcuts.union(aif.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 = new PerTargetInstantiationModelPointcut(this.declaredPointcut, preInstantiationPointcut, aif);
            this.lazy = true;
        }
        else {
            // A singleton aspect.
            this.instantiatedAdvice = `instantiateAdvice`(this.declaredPointcut);
            this.pointcut = declaredPointcut;
            this.lazy = false;
        }
    }
private Advice instantiateAdvice(AspectJExpressionPointcut pcut) {
        return this.atAspectJAdvisorFactory.getAdvice(
                this.method, pcut, this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
    }

//@Before(“say()”),@After(“say()”)增強器是不一樣的,所以就需要不同的增強器完成不同的邏輯。下面方法的swtich case 就一目瞭然了

public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut ajexp,
            MetadataAwareAspectInstanceFactory aif, int declarationOrderInAspect, String aspectName) {

        Class<?> candidateAspectClass = aif.getAspectMetadata().getAspectClass();
        validate(candidateAspectClass);

        AspectJAnnotation<?> aspectJAnnotation =
                AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
        if (aspectJAnnotation == null) {
            return null;
        }

        // If we get here, we know we have an AspectJ method.
        // Check that it's an AspectJ-annotated class
        if (!isAspect(candidateAspectClass)) {
            throw new AopConfigException("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 AtBefore:
                springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, ajexp, aif);
                break;
            case AtAfter:
                springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, ajexp, aif);
                break;
            case AtAfterReturning:
                springAdvice = new AspectJAfterReturningAdvice(candidateAdviceMethod, ajexp, aif);
                AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
                if (StringUtils.hasText(afterReturningAnnotation.returning())) {
                    springAdvice.setReturningName(afterReturningAnnotation.returning());
                }
                break;
            case AtAfterThrowing:
                springAdvice = new AspectJAfterThrowingAdvice(candidateAdviceMethod, ajexp, aif);
                AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
                if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
                    springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
                }
                break;
            case AtAround:
                springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, ajexp, aif);
                break;
            case AtPointcut:
                if (logger.isDebugEnabled()) {
                    logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
                }
                return null;
            default:
                throw new UnsupportedOperationException(
                        "Unsupported advice type on method " + candidateAdviceMethod);
        }

        // Now to configure the advice...
        springAdvice.setAspectName(aspectName);
        springAdvice.setDeclarationOrder(declarationOrderInAspect);
        String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
        if (argNames != null) {
            springAdvice.setArgumentNamesFromStringArray(argNames);
        }
        springAdvice.calculateArgumentBindings();
        return springAdvice;
    }

我們看一下AspectJMethodBeforeAdvice的實現

public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice, Serializable {

    public AspectJMethodBeforeAdvice(
            Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {

        super(aspectJBeforeAdviceMethod, pointcut, aif);
    }


    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        invokeAdviceMethod(getJoinPointMatch(), null, null);
    }

    @Override
    public boolean isBeforeAdvice() {
        return true;
    }

    @Override
    public boolean isAfterAdvice() {
        return false;
    }

}

這個before方法是在什麼時候呼叫的呢

假設的代理類是通過jdk方式
看一下JdkDynamicAopProxy的invoke方法

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

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

        try {
        //equals方法處理
            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                // The target does not implement the equals(Object) method itself.
                return equals(args[0]);
            }
    //hash方法處理      
            if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                // The target does not implement the hashCode() method itself.
                return 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;
//有時候目標物件內部的自我呼叫將無法實施切面中的增強則需要通過此屬性暴露代理
            if (this.advised.exposeProxy) {
                // Make invocation available if necessary.
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }

            // May be null. 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();
            }

            //獲取當前方法的攔截器鏈
            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()) {
                //如果沒有任何攔截器那麼直接呼叫切點方法
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
            }
            else {
                //將攔截器封裝在ReflectiveMethodInvocation
                // 便於使用proceed進行連結表用攔截器
                invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                //執行攔截器鏈
                retVal = invocation.proceed();
            }

            // Massage return value if necessary.
            Class<?> returnType = method.getReturnType();
            if (retVal != null && retVal == target && 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;
            }
            else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
                throw new AopInvocationException(
                        "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);
            }
        }
    }
@Override
    public Object proceed() throws Throwable {
        //  執行完所有增強後執行切點方法
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return invokeJoinpoint();
        }
//獲取下一個要執行的攔截器
        Object interceptorOrInterceptionAdvice =
                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            // 動態匹配
            InterceptorAndDynamicMethodMatcher dm =
                    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
                return dm.interceptor.invoke(this);
            }
            else {
                // 不匹配不執行攔截器
                return proceed();
            }
        }
        else {
            /*普通攔截器,直接呼叫攔截器,比如:
            *AspectJAroundAdvice
            *AspectJAfterAdvice
            *MethodBeforeAdviceInterceptor
            *ExposeInvocationInterceptor
            *DelegatePerTargetObjectIntroductionInterceptor
            */
            //將this作為引數傳遞保證當前例項中呼叫鏈的執行
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }