Spring源碼核心剖析

語言: CN / TW / HK

作者:京東科技 韓國凱

前言

SpringAOP作為Spring最核心的能力之一,其重要性不言而喻。然後需要知道的是AOP並不只是Spring特有的功能,而是一種思想,一種通用的功能。而SpringAOP只是在AOP的基礎上將能力集成到SpringIOC中,使其作為bean的一種,從而我們能夠很方便的進行使用。

一、SpringAOP的使用方式

1.1 使用場景

當我們在日常業務開發中,例如有些功能模塊是通用的(日誌、權限等),或者我們需要在某些功能前後去做一些增強,例如在某些方法執行後發送一條mq消息等。

如果我們將這些通用模塊代碼與業務代碼放在一塊,那麼每個業務代碼都要寫這些通用模塊,維護成本與耦合情況都十分嚴重。

因此,我們可以將此模塊抽象出來,就有了”切面“的概念。

1.2 常用方式

AOP的使用方式相對比較簡單,首先我們需要完成業務代碼

@Service
public class AopDemo implements AopInterface{

    public Student start(String name) {
        System.out.println("執行業務邏輯代碼.....");
        return new Student(name);
    }

}

業務邏輯比較簡單,接收一個name參數。

接下來我們需要創建其對應的切面

//將該切面加入spring容器
@Service
//聲明該類為一個切面
@Aspect
class AopAspect {

    //聲明要進行代理的方法
    @Pointcut("execution(* com.example.demo.aop.AopInterface.start(..))")
    public void startAspect() {
    }

    //在方法執行之前的邏輯
    @Before(value = "startAspect()")
    public void beforeAspect() {
        System.out.println("業務邏輯前代碼.....");
    }

    //在方法執行之後的邏輯
    @After(value = "startAspect()")
    public void afterAspect() {
        System.out.println("業務邏輯後代碼.....");
    }

    //圍繞方法前後的邏輯
    @Around("startAspect()")
    public Object aroundAspect(ProceedingJoinPoint point) throws Throwable {
        Object[] requestParams = point.getArgs();
        String name = requestParams[0].toString();
        System.out.println("傳入參數:" + name);
        requestParams[0] = "bob";
        return point.proceed(requestParams);
    }

}

可以看到,首先需要我們指明要代理的對象及方法,然後根據需要選擇不同的註解即可實現代理對象。

傳入參數:tom
業務邏輯前代碼.....
執行業務邏輯代碼.....
業務邏輯後代碼.....

二、SpringAOP源碼解析

2.1 被代理對象的開始initializeBean

根據上面的使用情況,我們知道只需要聲明對應的註解即可,不需要其他額外的配置,然後我們獲得的bean對象就已經是被代理的了,那麼我們可以推斷代理對象的過程一定是發生在bean創建的過程的。

我們回顧一下創建bean的流程

  1. 實例化bean

  2. 裝配屬性

  3. 初始化bean

只有第三步初始化bean的時候才會有機會進行代理。

找到對應的代碼位置:

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
   Object wrappedBean = bean;
   if (mbd == null || !mbd.isSynthetic()) {
      //前置處理器
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   }
	 //...
   try {
      //對象的初始化方法
      invokeInitMethods(beanName, wrappedBean, mbd);
   }
   if (mbd == null || !mbd.isSynthetic()) {
      //後置處理器,AOP開始的地方
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }

   return wrappedBean;
}

2.2 後置處理器applyBeanPostProcessorsAfterInitialization

後置處理器會執行那些實現了後置處理器接口的代碼:

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
      throws BeansException {

   Object result = existingBean;
   //獲取所有的後置處理器
   for (BeanPostProcessor processor : getBeanPostProcessors()) {
      //實現其要執行的方法
      Object current = processor.postProcessAfterInitialization(result, beanName);
      if (current == null) {
         return result;
      }
      result = current;
   }
   return result;
}

而AOP的後置處理器就是其中的一個: AbstractAutoProxyCreator

其對應的方法為(以下代碼不為同一個類,而是對應的執行順序):

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
   if (bean != null) {
      Object cacheKey = getCacheKey(bean.getClass(), beanName);
      if (this.earlyProxyReferences.remove(cacheKey) != bean) {
         //執行到下面方法
         return wrapIfNecessary(bean, beanName, cacheKey);
      }
   }
   return bean;
}

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		// 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;
		}

		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
}

protected Object createProxy(Class beanClass, @Nullable String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {

		//獲取advisors
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		proxyFactory.addAdvisors(advisors);
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}

		// Use original ClassLoader if bean class not locally loaded in overriding class loader
		ClassLoader classLoader = getProxyClassLoader();
		if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
			classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
		}
    //通過代理工廠創建代理對象
		return proxyFactory.getProxy(classLoader);
}

public Object getProxy(@Nullable ClassLoader classLoader) {
    //首先獲取對應的代理
		return createAopProxy().getProxy(classLoader);
}

//該方法根據要被代理的類選擇使用jdk代理還是cglib代理
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		if (!NativeDetector.inNativeImage() &&
				(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
			Class targetClass = config.getTargetClass();
      //如果被代理的類是一個接口則使用jdk代理
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) 			{
				return new JdkDynamicAopProxy(config);
			}
      //否則使用cglib代理
			return new ObjenesisCglibAopProxy(config);
		}
		else {
      //根據配置選擇強制使用jdk代理
			return new JdkDynamicAopProxy(config);
		}
}

我們知道,代理方式有jdk動態代理與cglib動態代理兩種方式,而我們一個bean使用那種代理方式則由上述的方法決定。

至此,我們已經確定了使用那種代理方式獲取代理對象。

2.3 獲取代理對象

從上文中,我們已經確定了選用何種方式構建代理對象。接下來就是通過不同的方式是如何獲取代理對象的。

看懂本章需要實現瞭解jdk動態代理或者cglib動態代理的方式。

2.3.1 JDK代理

首先在獲取代理對象時選擇 JdkDynamicAopProxy

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動態代理的概念)

JDK通過反射創建對象,效率上來説相對低一些。

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

		try {
			// 獲取被代理對象的所有切入點
			List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

			// 如果調用鏈路為空説明沒有需要執行的切入點,直接執行對應的方法即可
			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 {
				// 如果有切入點的話則按照切入點順序開始執行
				MethodInvocation invocation =
						new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				// Proceed to the joinpoint through the interceptor chain.
				retVal = invocation.proceed();
			}
			
			return retVal;
		}
}

invocation.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();
   }

   Object interceptorOrInterceptionAdvice =
         this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
   if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
      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 {
         // 繼續執行
         return proceed();
      }
   }
   else {
      // 如果調用鏈路還持續的話,下一個方法仍會調用proceed()
      return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
   }
}

2.3.2 cglib代理

public Object getProxy(@Nullable ClassLoader classLoader) {

   try {
      //配置CGLIB Enhancer...
      Enhancer enhancer = createEnhancer();
      if (classLoader != null) {
         enhancer.setClassLoader(classLoader);
         if (classLoader instanceof SmartClassLoader &&
               ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
            enhancer.setUseCache(false);
         }
      }
      enhancer.setSuperclass(proxySuperClass);
      enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
      enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
      enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));

      //1.獲取回調函數,對於代理類上所有方法的調用,都會調用CallBack,而Callback則需要實現intercept()方法
      Callback[] callbacks = getCallbacks(rootClass);
      Class[] types = new Class[callbacks.length];
      for (int x = 0; x < types.length; x++) {
         types[x] = callbacks[x].getClass();
      }
      // fixedInterceptorMap only populated at this point, after getCallbacks call above
      enhancer.setCallbackFilter(new ProxyCallbackFilter(
            this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
      enhancer.setCallbackTypes(types);

      //2.創建代理對象
      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);
   }
}

可以看到我們在創建代理對象前會先獲取代理對象的所有回調函數:

image-20230310174107202

首先可以看到我們一共有7個回調方法,其中第一個為AOP相關的方法,其他的為spring相關。

在第一個對調對象中持有的 advised對象中有 advisors屬性,就是對應我們的代理類中四個切片,@Before等等。

然後我們看一下 createProxyClassAndInstance()都做了什麼。

//CglibAopProxy類的創建代理對象方法
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
   enhancer.setInterceptDuringConstruction(false);
   enhancer.setCallbacks(callbacks);
   return (this.constructorArgs != null && this.constructorArgTypes != null ?
         enhancer.create(this.constructorArgTypes, this.constructorArgs) :
         enhancer.create());
}

//ObjenesisCglibAopProxy繼承了CglibAopProxy類,並覆寫了其方法
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
		Class proxyClass = enhancer.createClass();
		Object proxyInstance = null;

    //1.嘗試使用objenesis創建對象
		if (objenesis.isWorthTrying()) {
			try {
				proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache());
			}
			catch (Throwable ex) {
				logger.debug("Unable to instantiate proxy using Objenesis, " +
						"falling back to regular proxy construction", ex);
			}
		}

    //2.根據commit的提交記錄發現,objenesis有可能創建對象失敗,如果失敗的話則選用放射的方式創建對象
		if (proxyInstance == null) {
			// Regular instantiation via default constructor...
			try {
				Constructor ctor = (this.constructorArgs != null ?
						proxyClass.getDeclaredConstructor(this.constructorArgTypes) :
						proxyClass.getDeclaredConstructor());
				ReflectionUtils.makeAccessible(ctor);
				proxyInstance = (this.constructorArgs != null ?
						ctor.newInstance(this.constructorArgs) : ctor.newInstance());
			}
			catch (Throwable ex) {
				throw new AopConfigException("Unable to instantiate proxy using Objenesis, " +
						"and regular proxy instantiation via default constructor fails as well", ex);
			}
		}

    //
		((Factory) proxyInstance).setCallbacks(callbacks);
		return proxyInstance;
	}

2.3.3 cglib

此處有個遇到的問題,當我在debug的時候,發現怎麼都進不去 createProxyClassAndInstance(),百思不得其解,然後看到IDEA旁邊有一個向下的箭頭,代表該方法可能其子類被覆寫了。然後在其子類處打斷點果然發現是其子類的實現。

此處在2.2中也可看到:

image-20230310174806723

可以看到返回的是其子類的對象,而不是CglibAopProxy本身的對象。