Core Analysis of Spring Source Code | JD Cloud Technical Team

foreword

As one of Spring's core capabilities, Spring AOP's importance is self-evident. Then what you need to know is that AOP is not just a Spring-specific function, but an idea, a general function. And Spring AOP just integrates the capability into Spring IOC on the basis of AOP, making it a kind of bean, so that we can use it very conveniently.

1. How to use Spring AOP

1.1 Usage Scenarios

When we are in daily business development, for example, some functional modules are common (logs, permissions, etc.), or we need to make some enhancements before and after certain functions, such as sending an mq message after certain methods are executed.

If we put these common module codes and business codes together, then each business code must write these common modules, and the maintenance cost and coupling are very serious.

Therefore, we can abstract this module and have the concept of "aspect".

1.2 Commonly used methods

The use of AOP is relatively simple, first we need to complete the business code

@Service
public class AopDemo implements AopInterface{

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

}

The business logic is relatively simple, receiving a name parameter.

Next we need to create its corresponding aspect

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

}

It can be seen that first we need to specify the object and method to be proxied, and then select different annotations according to the needs to realize the proxy object.

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

Two, SpringAOP source code analysis

2.1 The start of the proxy object initializeBean

According to the above usage, we know that we only need to declare the corresponding annotations, no other additional configuration is required, and then the bean object we get is already proxied, then we can infer that the process of proxiing the object must occur in The process of bean creation.

Let's review the process of creating beans

  1. instantiated bean
  2. assembly properties
  3. initialize beans

Only when the bean is initialized in the third step will there be a chance to proxy.

Find the corresponding code location:

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 processor applyBeanPostProcessorsAfterInitialization

Post-processors execute code that implements the post-processor interface:

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

And AOP's post processor is one of them: AbstractAutoProxyCreator

The corresponding method is (the following code is not the same class, but the corresponding execution sequence):

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

We know that there are two proxy methods: jdk dynamic proxy and cglib dynamic proxy, and which proxy method we use for a bean is determined by the above method.

So far, we have determined which proxy method to use to obtain the proxy object.

2.3 Get proxy object

From the above, we have determined which way to choose to construct the proxy object. The next step is how to obtain proxy objects in different ways.

To understand this chapter, you need to understand the way of jdk dynamic proxy or cglib dynamic proxy.

2.3.1 JDK Proxy

First select JdkDynamicAopProxy when getting the proxy object

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

When the proxy object executes the proxy method , it will enter this method. (The concept of jdk dynamic proxy)

JDK creates objects through reflection, which is relatively inefficient.

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(); This method executes all invocation links recursively.

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 proxy

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

You can see that we will get all the callback functions of the proxy object before creating the proxy object:

First of all, we can see that we have a total of 7 callback methods, the first of which is related to AOP, and the others are related to spring.

There are advisors attributes in the advised object held in the first swap object, which correspond to the four slices in our proxy class, @Before and so on.

Then we look at what createProxyClassAndInstance() does.

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

There is a problem encountered here. When I was debugging, I found that I couldn’t get into createProxyClassAndInstance(). I couldn’t figure it out. Then I saw a downward arrow next to IDEA, which means that the method may have subclasses. Class is overridden. Then the break point at its subclass was found to be the implementation of its subclass.

Also seen here in 2.2:

It can be seen that the object of its subclass is returned, not the object of CglibAopProxy itself.

Author: Han Kai of JD Technology

Source: JD Cloud Developer Community

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

Guess you like

Origin my.oschina.net/u/4090830/blog/10084133