首页 > 编程语言 >【Spring IOC】【七】容器源码解析- PostConstruct、PreDestory的源码分析

【Spring IOC】【七】容器源码解析- PostConstruct、PreDestory的源码分析

时间:2023-02-18 23:44:38浏览次数:48  
标签:解析 Spring clazz bean 源码 new PreDestory method metadata

1  前言

@PostConstruct、@PreDestory这两个注解大家应该有用过吧,我们这篇分析一下主要是PostConstruct这个注解的解析时机和执行时机。

2  源码分析

2.1  解析时机-doCreateBean的applyMergedBeanDefinitionPostProcessors

首先是解析时机,就是我们的这个@PostConstruct注解是什么时候被分析的,CommonAnnotationBeanPostProcessor这个后置处理器还知道的吧,我们说过这个是在populateBean的时候会分析@Resource注解,这里它也会参与到@PostConstruct和@PreDestory,看他的初始化方法会将这两个注解,放入到集合中,它的父类是InitDestroyAnnotationBeanPostProcessor,那么两者有什么关联呢,分析源码如下:

这里是解析时机的入口,也就是doCreateBean方法这里会调用到InitDestroyAnnotationBeanPostProcessor的postProcessMergedBeanDefinition方法,来分析bean的postConstruct、preDestory,注意只是解析,并不会执行,解析并放进缓存中:

解析放进缓存中,并不会执行。

// 分析bean
private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
  if (this.lifecycleMetadataCache == null) {
    // Happens after deserialization, during destruction...
    return buildLifecycleMetadata(clazz);
  }
  // Quick check on the concurrent map first, with minimal locking.
  LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);
  if (metadata == null) {
    synchronized (this.lifecycleMetadataCache) {
      metadata = this.lifecycleMetadataCache.get(clazz);
      if (metadata == null) {
        metadata = buildLifecycleMetadata(clazz);
        // 放进缓存中
        this.lifecycleMetadataCache.put(clazz, metadata);
      }
      return metadata;
    }
  }
  return metadata;
}// 返回LifecycleMetadata对象
private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
  // this.initAnnotationType 里边有PostConstruct注解
  // this.destroyAnnotationType 里边有PreDestory注解
  if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
    return this.emptyLifecycleMetadata;
  }

  List<LifecycleElement> initMethods = new ArrayList<>();
  List<LifecycleElement> destroyMethods = new ArrayList<>();
  Class<?> targetClass = clazz;

  do {
    final List<LifecycleElement> currInitMethods = new ArrayList<>();
    final List<LifecycleElement> currDestroyMethods = new ArrayList<>();

    ReflectionUtils.doWithLocalMethods(targetClass, method -> {
    // 判断方法是由有PostConstruct注解
    if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
      LifecycleElement element = new LifecycleElement(method);
      // 有的话就添加进currInitMethods里
      currInitMethods.add(element);
            // 判断方法是由有PreDestory注解
      if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
      // 有的话就添加进currDestroyMethods里
      currDestroyMethods.add(new LifecycleElement(method));
             
       initMethods.addAll(0, currInitMethods);
      destroyMethods.addAll(currDestroyMethods);
      targetClass = targetClass.getSuperclass();
  }   while (targetClass != null && targetClass != Object.class);   return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata : new LifecycleMetadata(clazz, initMethods, destroyMethods)); }

解析时机大概的流程如下:

  1. doCreateBean为入口调用applyMergedBeanDefinitionPostProcessors
  2. InitDestroyAnnotationBeanPostProcessor的postProcessMergedBeanDefinition执行进行bean的解析返回
  3. 解析完得到LifecycleMetadata并缓存到lifecycleMetadataCache

2.2  执行时机-initializeBean中执行前置处理applyBeanPostProcessorsBeforeInitialization

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
  try {
    metadata.invokeInitMethods(bean, beanName);
  }
  catch (InvocationTargetException ex) {
    throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
  }
  catch (Throwable ex) {
    throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
  }
  return bean;
}
public void invokeInitMethods(Object target, String beanName) throws Throwable {
  Collection<LifecycleElement> checkedInitMethods = this.checkedInitMethods;
  Collection<LifecycleElement> initMethodsToIterate =
                    (checkedInitMethods != null ? checkedInitMethods : this.initMethods);
  if (!initMethodsToIterate.isEmpty()) {
    for (LifecycleElement element : initMethodsToIterate) {
      if (logger.isTraceEnabled()) {
        logger.trace("Invoking init method on bean '" + beanName + "': " + element.getMethod());
      }
      // 反射执行
      element.invoke(target);
    }
  }
}

3  小结

哦的肯不,一个字巧妙,有哪里理解不对的,还望指正奥,加油。

标签:解析,Spring,clazz,bean,源码,new,PreDestory,method,metadata
From: https://www.cnblogs.com/kukuxjx/p/17133927.html

相关文章