Análise básica do código-fonte do Spring | Equipe técnica do JD Cloud

prefácio

Como um dos principais recursos do Spring, a importância do Spring AOP é evidente. Então o que você precisa saber é que o AOP não é apenas uma função específica do Spring, mas uma ideia, uma função geral. E o Spring AOP apenas integra a capacidade no Spring IOC com base no AOP, tornando-o uma espécie de bean, para que possamos usá-lo de maneira muito conveniente.

1. Como usar o Spring AOP

1.1 Cenários de Uso

Quando estamos no desenvolvimento diário de negócios, por exemplo, alguns módulos funcionais são comuns (logs, permissões, etc.), ou precisamos fazer algumas melhorias antes e depois de determinadas funções, como enviar uma mensagem mq após a execução de determinados métodos.

Se colocarmos esses códigos de módulo comuns e códigos de negócios juntos, então cada código de negócios deve escrever esses módulos comuns, e o custo de manutenção e o acoplamento são muito sérios.

Portanto, podemos abstrair este módulo e ter o conceito de "aspecto".

1.2 Métodos comumente usados

A utilização do AOP é relativamente simples, primeiro precisamos preencher o código do negócio

@Service
public class AopDemo implements AopInterface{

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

}

A lógica de negócio é relativamente simples, recebendo um parâmetro name.

Em seguida, precisamos criar seu aspecto correspondente

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

}

Pode-se ver que primeiro precisamos especificar o objeto e o método a ser proxy e, em seguida, selecionar diferentes anotações de acordo com as necessidades para realizar o objeto proxy.

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

Dois, análise de código-fonte SpringAOP

2.1 O início do objeto proxy initializeBean

De acordo com o uso acima, sabemos que precisamos apenas declarar as anotações correspondentes, nenhuma outra configuração adicional é necessária e, em seguida, o objeto bean que obtemos já é proxy, então podemos inferir que o processo de proxy do objeto deve ocorrer em O processo de criação do feijão.

Vamos revisar o processo de criação de beans

  1. bean instanciado
  2. propriedades de montagem
  3. inicializar feijões

Somente quando o bean for inicializado na terceira etapa haverá uma chance de proxy.

Encontre o local do código correspondente:

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 pós-processador applyBeanPostProcessorsAfterInitialization

Os pós-processadores executam o código que implementa a interface do pós-processador:

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

E o pós-processador do AOP é um deles: AbstractAutoProxyCreator

O método correspondente é (o código a seguir não é a mesma classe, mas a sequência de execução correspondente):

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

Sabemos que existem dois métodos de proxy: jdk dynamic proxy e cglib dynamic proxy, e qual método de proxy usamos para um bean é determinado pelo método acima.

Até agora, determinamos qual método proxy usar para obter o objeto proxy.

2.3 Obter objeto proxy

A partir do exposto, determinamos qual caminho escolher para construir o objeto proxy. A próxima etapa é como obter objetos proxy de diferentes maneiras.

Para entender este capítulo, você precisa entender o caminho do proxy dinâmico jdk ou do proxy dinâmico cglib.

2.3.1 Proxy JDK

Primeiro selecione JdkDynamicAopProxy ao obter o objeto 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);
}

Quando o objeto proxy executar o método proxy , ele entrará neste método. (O conceito de proxy dinâmico jdk)

O JDK cria objetos por meio de reflexão, o que é relativamente ineficiente.

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(); Este método executa todos os links de invocação recursivamente.

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

Você pode ver que obteremos todas as funções de callback do objeto proxy antes de criar o objeto proxy:

Em primeiro lugar, podemos ver que temos um total de 7 métodos de callback, sendo o primeiro relacionado ao AOP e os demais relacionados ao spring.

Existem atributos de conselheiros no objeto aconselhado mantido no primeiro objeto de troca, que correspondem às quatro fatias em nossa classe de proxy, @Before e assim por diante.

Em seguida, veremos o que createProxyClassAndInstance() faz.

//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

Há um problema encontrado aqui. Quando eu estava depurando, descobri que não conseguia entrar em createProxyClassAndInstance(). Não consegui descobrir. Então vi uma seta para baixo ao lado de IDEA, o que significa que o método pode ter subclasses. A classe é substituída. Em seguida, descobriu-se que o ponto de interrupção em sua subclasse era a implementação de sua subclasse.

Também visto aqui em 2.2:

Pode-se ver que o objeto de sua subclasse é retornado, não o objeto de CglibAopProxy em si.

Autor: Han Kai da JD Technology

Fonte: JD Cloud Developer Community

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

Acho que você gosta

Origin my.oschina.net/u/4090830/blog/10084133
Recomendado
Clasificación