Analyse de base du code source Spring | Équipe technique JD Cloud

avant-propos

En tant que l'une des principales capacités de Spring, l'importance de Spring AOP est évidente. Ensuite, ce que vous devez savoir, c'est qu'AOP n'est pas seulement une fonction spécifique à Spring, mais une idée, une fonction générale. Et Spring AOP intègre simplement la capacité dans Spring IOC sur la base d'AOP, ce qui en fait une sorte de haricot, de sorte que nous pouvons l'utiliser très facilement.

1. Comment utiliser Spring AOP

1.1 Scénarios d'utilisation

Lorsque nous sommes dans le développement commercial quotidien, par exemple, certains modules fonctionnels sont communs (journaux, autorisations, etc.), ou nous devons apporter des améliorations avant et après certaines fonctions, comme l'envoi d'un message mq après l'exécution de certaines méthodes.

Si nous rassemblons ces codes de modules communs et ces codes métiers, alors chaque code métier doit écrire ces modules communs, et les coûts de maintenance et de couplage sont très importants.

Par conséquent, nous pouvons abstraire ce module et avoir le concept "d'aspect".

1.2 Méthodes couramment utilisées

L'utilisation d'AOP est relativement simple, il faut d'abord compléter le code métier

@Service
public class AopDemo implements AopInterface{

    public Student start(String name) {
        System.out.println("执行业务逻辑代码.....");
        return new Student(name);
    }

}

La logique métier est relativement simple, recevant un paramètre de nom.

Ensuite, nous devons créer son aspect correspondant

//将该切面加入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);
    }

}

On peut voir que nous devons d'abord spécifier l'objet et la méthode à proxy, puis sélectionner différentes annotations en fonction des besoins pour réaliser l'objet proxy.

传入参数:tom
业务逻辑前代码.....
执行业务逻辑代码.....
业务逻辑后代码.....

Deux, analyse du code source SpringAOP

2.1 Le début de l'objet proxy initializeBean

Selon l'utilisation ci-dessus, nous savons que nous n'avons qu'à déclarer les annotations correspondantes, aucune autre configuration supplémentaire n'est requise, puis l'objet bean que nous obtenons est déjà proxy, alors nous pouvons en déduire que le processus de proxy de l'objet doit se produire dans Le processus de création du haricot.

Passons en revue le processus de création de beans

  1. haricot instancié
  2. propriétés d'assemblage
  3. initialiser les haricots

Ce n'est que lorsque le bean est initialisé à la troisième étape qu'il y aura une chance de proxy.

Trouvez l'emplacement de code correspondant :

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 post-processeur applyBeanPostProcessorsAfterInitialization

Les post-processeurs exécutent du code qui implémente l'interface post-processeur :

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;
}

Et le post-processeur d'AOP en fait partie : AbstractAutoProxyCreator

La méthode correspondante est (le code suivant n'est pas la même classe, mais la séquence d'exécution correspondante) :

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);
		}
}

Nous savons qu'il existe deux méthodes de proxy : le proxy dynamique jdk et le proxy dynamique cglib, et la méthode de proxy que nous utilisons pour un bean est déterminée par la méthode ci-dessus.

Jusqu'à présent, nous avons déterminé quelle méthode proxy utiliser pour obtenir l'objet proxy.

2.3 Obtenir un objet proxy

À partir de ce qui précède, nous avons déterminé la manière de choisir pour construire l'objet proxy. L'étape suivante consiste à obtenir des objets proxy de différentes manières.

Pour comprendre ce chapitre, vous devez comprendre le fonctionnement du proxy dynamique jdk ou du proxy dynamique cglib.

2.3.1 Proxy JDK

Sélectionnez d'abord JdkDynamicAopProxy lors de l'obtention de l'objet proxy

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);
}

Lorsque l' objet proxy exécute la méthode proxy , il entrera dans cette méthode. (Le concept de proxy dynamique jdk)

JDK crée des objets par réflexion, ce qui est relativement inefficace.

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(); Cette méthode exécute tous les liens d'invocation de manière récursive.

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 Proxy 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);
   }
}

Vous pouvez voir que nous obtiendrons toutes les fonctions de rappel de l'objet proxy avant de créer l'objet proxy :

Tout d'abord, nous pouvons voir que nous avons un total de 7 méthodes de rappel, dont la première est liée à AOP, et les autres sont liées au printemps.

Il y a des attributs de conseillers dans l'objet conseillé contenu dans le premier objet d'échange, qui correspondent aux quatre tranches de notre classe proxy, @Before et ainsi de suite.

Ensuite, nous regardons ce que fait 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

Il y a un problème rencontré ici. Lors du débogage, j'ai constaté que je ne pouvais pas entrer dans createProxyClassAndInstance(). Je ne pouvais pas le comprendre. Ensuite, j'ai vu une flèche vers le bas à côté de IDEA, ce qui signifie que la méthode peut avoir sous-classes. La classe est remplacée. Ensuite, le point d'arrêt de sa sous-classe s'est avéré être l'implémentation de sa sous-classe.

Aussi vu ici en 2.2 :

On peut voir que l'objet de sa sous-classe est retourné, pas l'objet de CglibAopProxy lui-même.

Auteur : Han Kai de JD Technology

Source : Communauté de développeurs JD Cloud

{{o.name}}
{{m.name}}

Je suppose que tu aimes

Origine my.oschina.net/u/4090830/blog/10084133
conseillé
Classement