本文正在参与「金石计划」

作者:京东科技 韩国凯

前语

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](https://www.6hu.cc/wp-content/uploads/2023/05/1683183276-4f6fed4e395807f.png)

首要能够看到咱们一共有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](https://www.6hu.cc/wp-content/uploads/2023/05/1683183282-1e85d9fda21bbb5.png)

能够看到回来的是其子类的目标,而不是`CglibAopProxy`本身的目标。