Sping AOP

minororange發表於2021-12-06

AOP

spring 中的開啟 AOP 步驟:

  1. @EnableAspectJAutoProxy :註冊一個 AspectJAutoProxyRegistrar bean 物件:AnnotationAwareAspectJAutoProxyCreator
  2. @AspectJ :標記一個 class 為增強類
  3. @Before 、@After…: 標記一個方法為某節點的切面

代理類建立流程

doGetBean —> createBean —> resolveBeforeInstantiation —> applyBeanPostProcessorsBeforeInstantiation —> postProcessBeforeInstantiation —> applyBeanPostProcessorsAfterInitialization —> postProcessAfterInitialization —> wrapIfNecessary —> createProxy —> getProxy —> getCallbacks

  • org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

    protected <T> T doGetBean(
              String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
              throws BeansException {
          ....省略部分程式碼
    
           // bean 定義中是否為單例
                  // Create bean instance.
                  if (mbd.isSingleton()) {
                      sharedInstance = getSingleton(beanName, () -> {
                          try {
                // 建立 bean
                              return createBean(beanName, mbd, args);
                          }
                          catch (BeansException ex) {
                              // Explicitly remove instance from singleton cache: It might have been put there
                              // eagerly by the creation process, to allow for circular reference resolution.
                              // Also remove any beans that received a temporary reference to the bean.
                              destroySingleton(beanName);
                              throw ex;
                          }
                      });
                      beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                  }
    
          return adaptBeanInstance(name, beanInstance, requiredType);
      }
  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException {

        try {
      // 嘗試建立代理類
            // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
        }
        catch (Throwable ex) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                    "BeanPostProcessor before instantiation of bean failed", ex);
        }

    }
  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
        Object bean = null;
        if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
            // Make sure bean class is actually resolved at this point.
            if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
                Class<?> targetType = determineTargetType(beanName, mbd);
                if (targetType != null) {

                    bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                    if (bean != null) {

                        bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                    }
                }
            }
            mbd.beforeInstantiationResolved = (bean != null);
        }
        return bean;
    }
  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInstantiation
  • org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation
  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
  • org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary

  • org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy
proxyFactory.getProxy(classLoader);
  • org.springframework.aop.framework.CglibAopProxy#getProxy(java.lang.ClassLoader)
@Override
    public Object getProxy(@Nullable ClassLoader classLoader) {

        try {
       //  被代理的類
            Class<?> rootClass = this.advised.getTargetClass();
          ...
      // 獲取 callbacks
            Callback[] callbacks = getCallbacks(rootClass);
            Class<?>[] types = new Class<?>[callbacks.length];
            ...
      // 生成代理類
            return createProxyClassAndInstance(enhancer, callbacks);
        }
        catch (CodeGenerationException | IllegalArgumentException ex) {
            throw new AopConfigException("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
            throw new AopConfigException("Unexpected AOP exception", ex);
        }
    }

org.springframework.aop.framework.CglibAopProxy#getCallbacks

private Callback[] getCallbacks(Class<?> rootClass) throws Exception {

     // 將切面方法轉化為 DynamicAdvisedInterceptor
        // Choose an "aop" interceptor (used for AOP calls). 
        Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

        Callback[] mainCallbacks = new Callback[] {
                aopInterceptor,  // for normal advice
                targetInterceptor,  // invoke target without considering advice, if optimized
                new SerializableNoOp(),  // no override for methods mapped to this
                targetDispatcher, this.advisedDispatcher,
                new EqualsInterceptor(this.advised),
                new HashCodeInterceptor(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 = new Callback[methods.length];
            this.fixedInterceptorMap = CollectionUtils.newHashMap(methods.length);

            // TODO: small memory optimization here (can skip creation for methods with no advice)
            for (int x = 0; x < methods.length; x++) {
                Method method = methods[x];
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass);
                fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
                        chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
                this.fixedInterceptorMap.put(method, x);
            }

            // Now copy both the callbacks from mainCallbacks
            // and fixedCallbacks into the callbacks array.
            callbacks = new Callback[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;
    }

增強方法執行流程


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 {
              // 獲取呼叫鏈
                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() && CglibMethodInvocation.isMethodProxyCompatible(method)) {
                    // 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);
                    try {
                        retVal = methodProxy.invoke(target, argsToUse);
                    }
                    catch (CodeGenerationException ex) {
                        CglibMethodInvocation.logFastClassGenerationFailure(method);
                        retVal = AopUtils.invokeJoinpointUsingReflection(target, method, 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);
                }
            }
        }

建立代理類時,會將 org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor#intercept 攔截器加入到 CGLIB 的 callback 中

圖片
org.springframework.aop.framework.ReflectiveMethodInvocation#proceed

public Object proceed() throws Throwable {
        // index 初始為 -1 ,如果當前 index 為最後一個,則執行被代理類的實際方法
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return invokeJoinpoint();
        }

    // 執行呼叫鏈邏輯
        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;
            Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
            if (dm.methodMatcher.matches(this.method, 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 {
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }

org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor#invoke

public Object invoke(MethodInvocation mi) throws Throwable {
    // 先執行當前攔截器的 before 方法,然後再呼叫呼叫鏈
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
        return mi.proceed();
    }

org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor#invoke

    public Object invoke(MethodInvocation mi) throws Throwable {
    // 先執行呼叫鏈,呼叫鏈執行完畢後,再執行 after 方法
        Object retVal = mi.proceed();
        this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
        return retVal;
    }
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章