Spring-BeanPostProcessor与AOP实现

Spring介绍四

Posted by Kang on September 15, 2019

  在《Spring-自身实例化与属性实例化》中我们提到“AOP功能就是用过InstantiationAwareBeanPostProcessor来实现的,其返回了对象的代理。”,现在来通过代码具体说明。

预获取

  直接看关注的核心代码,在createBean是先通过resolveBeforeInstantiation进行了代理类的调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
  //省略 ...
  try {
    // 通过Bean的后置创建处理器进行后置处理创建代理对象,一般情况下此处不会生成代理对象
    // 为何不管是我们的jdk代理还是cglib代理都不会再此处进行代理呢?
    // 答:因为我们的真实对象没有生成,所以这里不会生成代理对象。
    // 那么这个resolveBeforeInstantiation方法到底做什么?
    // 答:此处其实是AOP功能的核心要素,其在这个方法中对我们的AOP切面信息进行了缓存
    Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
    // 若存在代理,则直接返回,中断结束整个初始化流程
    if (bean != null) {
      return bean;
    }
  }
  //省略 ...

  try {
    Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    if (logger.isDebugEnabled()) {
      logger.debug("Finished creating instance of bean '" + beanName + "'");
    }
    return beanInstance;
  }
  //省略 ...
}

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
  Object bean = null;
  if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
    // Make sure bean class is actually resolved at this point.
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      Class<?> targetType = determineTargetType(beanName, mbd);
      if (targetType != null) {
        // 若存在则接着处理
        bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
        if (bean != null) {
          bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
        }
      }
    }
    mbd.beforeInstantiationResolved = (bean != null);
  }
  return bean;
}

  需要注意的是,applyBeanPostProcessorsBeforeInstantiation中存在targetSource,则直接在对象初始化之前进行创建代理, 避免了目标对象不必要的实例化。此处不存在targetSource,在完成实例化后,于initializeBean方法中接着调用applyBeanPostProcessorsBeforeInitialization和applyBeanPostProcessorsAfterInitialization进行处理。

BeanPostProcessor引入

AOP等切面信息缓存

  我们简单看下实例化前,对于BeanPostProcessor的使用。resolveBeforeInstantiation尝试获取一个targetSource,其子方法applyBeanPostProcessorsBeforeInstantiation循环处理了所有的InstantiationAwareBeanPostProcessor,我们主要看关于AOP的子类AnnotationAwareAspectJAutoProxyCreator,在其父类中AbstractAutoProxyCreator中对AOP切面信息进行解析缓存。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// AOP切面信息进行解析缓存
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
  Object cacheKey = getCacheKey(beanClass, beanName);

  if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
    if (this.advisedBeans.containsKey(cacheKey)) {
      return null;
    }
    // 是否是Advice、Pointcut、Advisor、AopInfrastructureBean
    // 判断是否是切面(判断是否有aspect注解,@Aspect注解)等特殊的bean处理
    if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
      this.advisedBeans.put(cacheKey, Boolean.FALSE);
      return null;
    }
  }

  // 获取targetSource, 如果存在则直接在对象初始化之前进行创建代理, 避免了目标对象不必要的实例化
  // 如果没有自定义TargetSource,则走到postProcessAfterInitialization方法创建代理
  TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
  if (targetSource != null) {
    if (StringUtils.hasLength(beanName)) {
      this.targetSourcedBeans.add(beanName);
    }
    // 查找当前类所有的有效的Advisors
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
    // 根据JDK或者cglib生成动态代理对象
    Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
    this.proxyTypes.put(cacheKey, proxy.getClass());
    return proxy;
  }

  return null;
}

实例化后的BeanPostProcessor(后置处理器)

  上面说到,只有在targetSource能获取到的时候才直接处理,否则将在对象初始化完成后initializeBean方法下的applyBeanPostProcessorsBeforeInitialization和applyBeanPostProcessorsAfterInitialization,我们简单看下实例化完成之后的调用beanProcessor#postProcessAfterInitialization来进行Bean的属性/行为的修改,也在这个地方实现了AOP功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// AbstractAutoProxyCreator.java

//bean实例化完成后处理
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
    throws BeansException {

  Object result = existingBean;
  for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
    Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
    if (current == null) {
      return result;
    }
    result = current;
  }
  return result;
}

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
  if (bean != null) {
    Object cacheKey = getCacheKey(bean.getClass(), beanName);
    if (!this.earlyProxyReferences.contains(cacheKey)) {
      return wrapIfNecessary(bean, beanName, cacheKey);
    }
  }
  return bean;
}

advice增强器代理包装

  对于AOP来说,我们关注AbstractAutoProxyCreator的postProcessAfterInitialization,其调用了wrapIfNecessary方法来对前面生成的代理对象进一步进行有条件包装:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
  // 省略 ...
  // 获取所有的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;
}

  若获取到了advice增强器,则将增强器作为一个链,设置在代理对象中,在invoke时进行调用。
  由于上面返回了对象的一个代理,所以在调用的时候通过代理对象进行对外服务,以jdk实现的代理对象为例,其invoke方法中引入了拦截链:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   // 省略 ...

    Object retVal;
    // 
    target = targetSource.getTarget();
    Class<?> targetClass = (target != null ? target.getClass() : null);

    // 获取拦截链
    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

    // Check whether we have any advice. If we don't, we can fallback on direct
    // reflective invocation of the target, and avoid creating a MethodInvocation.
    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 {
      // 若存在拦截链,则在ReflectiveMethodInvocation#invocation中递归调用拦截链
      invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
      // Proceed to the joinpoint through the interceptor chain.
      retVal = invocation.proceed();
    }
    // 省略 ...
}

拦截器链调用与AOP

  循环调用拦截器链,interceptor包含了根据配置解析拦截器:

  • MethodBeforeAdviceInterceptor 前置通知
  • AspectJAfterAdvice 后置通知
  • AfterReturningAdviceInterceptor 返回通知
  • AspectJAfterThrowingAdvice 异常通知
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    
    public Object proceed() throws Throwable {
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
       //执行目标方法
      return invokeJoinpoint();
    }
    
    Object interceptorOrInterceptionAdvice =
        this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
      // Evaluate dynamic method matcher here: static part will already have
      // been evaluated and found to match.
      InterceptorAndDynamicMethodMatcher dm =
          (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
      if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
        return dm.interceptor.invoke(this);
      }
      else {
        // Dynamic matching failed.
        // Skip this interceptor and invoke the next in the chain.
        return proceed();
      }
    }
    else {
      // It's an interceptor, so we just invoke it: The pointcut will have
      // been evaluated statically before this object was constructed.
      return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
    }