Spring ⑥ @Lazy 注解原理详解

spring-logo-0.jpg

Spring ⑥ @Lazy 注解原理详解

Spring 源码系列文章会遵循由浅入深,由易到难,由宏观到微观的原则,目标是尽量降低学习难度,而不是一上来就迷失在源码当中. 文章会从一个场景作为出发点,针对性的目的性极强的针对该场景对 Spring 的实现原理,源码进行探究学习。该系列文章会让你收获什么? 从对 Spring 的使用者成为 Spring 专家。该文章会同步在微信公众号 【DevXJava】, 方便在微信客户端阅读。

本章的内容是对 bean 创建过程中依赖项注入时 @Lazy 注解源码进行分析。

场景

public class LazyAnnotationExp {

    public static void main(String[] args) {
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

        AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
        processor.setBeanFactory(factory);
        factory.addBeanPostProcessor(processor);

        factory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());

        factory.registerBeanDefinition("bean1" , BeanDefinitionBuilder
                .genericBeanDefinition(Bean1.class)
                .getBeanDefinition());

        factory.registerBeanDefinition("bean2" , BeanDefinitionBuilder
                .genericBeanDefinition(Bean2.class)
                .getBeanDefinition());

        Bean1 bean1 = factory.getBean(Bean1.class);
        System.out.println("bean1 -> " + bean1);
        
        System.out.println(bean1.getBean2().toString());
        System.out.println(bean1.getBean2().toString());
    }

    @Data
    static class Bean1 {

        @Autowired
        @Lazy
        Bean2 bean2;

        public Bean1() {
            System.out.println("======================== bean1 实例化");
        }
    }

    static class Bean2 {

        public Bean2() {
            System.out.println("++++++++++++++++++++++++++ bean2 实例化");
        }
    }
}

@Lazy 注解可以起到对 bean 延迟加载的作用。

image.png

DefaultListableBeanFactory#resolveDependency

@Override
@Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
      @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

   descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
   if (Optional.class == descriptor.getDependencyType()) {
      return createOptionalDependency(descriptor, requestingBeanName);
   }
   else if (ObjectFactory.class == descriptor.getDependencyType() ||
         ObjectProvider.class == descriptor.getDependencyType()) {
      return new DependencyObjectProvider(descriptor, requestingBeanName);
   }
   else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
      return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
   }
   else {
      Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
            descriptor, requestingBeanName);
      if (result == null) {
         result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
      }
      return result;
   }
}

ContextAnnotationAutowireCandidateResolver#getLazyResolutionProxyIfNecessary

@Override
@Nullable
public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, @Nullable String beanName) {
   return (isLazy(descriptor) ? buildLazyResolutionProxy(descriptor, beanName) : null);
}

ContextAnnotationAutowireCandidateResolver#isLazy

protected boolean isLazy(DependencyDescriptor descriptor) {
   for (Annotation ann : descriptor.getAnnotations()) {
      Lazy lazy = AnnotationUtils.getAnnotation(ann, Lazy.class);
      if (lazy != null && lazy.value()) {
         return true;
      }
   }
   MethodParameter methodParam = descriptor.getMethodParameter();
   if (methodParam != null) {
      Method method = methodParam.getMethod();
      if (method == null || void.class == method.getReturnType()) {
         Lazy lazy = AnnotationUtils.getAnnotation(methodParam.getAnnotatedElement(), Lazy.class);
         if (lazy != null && lazy.value()) {
            return true;
         }
      }
   }
   return false;
}

ContextAnnotationAutowireCandidateResolver#buildLazyResolutionProxy

buildLazyResolutionProxy 方法中创建了代理对象。

protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final @Nullable String beanName) {
   BeanFactory beanFactory = getBeanFactory();
   Assert.state(beanFactory instanceof DefaultListableBeanFactory,
         "BeanFactory needs to be a DefaultListableBeanFactory");
   final DefaultListableBeanFactory dlbf = (DefaultListableBeanFactory) beanFactory;

   TargetSource ts = new TargetSource() {
      @Override
      public Class<?> getTargetClass() {
         return descriptor.getDependencyType();
      }
      @Override
      public boolean isStatic() {
         return false;
      }
      @Override
      public Object getTarget() {
         Set<String> autowiredBeanNames = (beanName != null ? new LinkedHashSet<>(1) : null);
         Object target = dlbf.doResolveDependency(descriptor, beanName, autowiredBeanNames, null);
         if (target == null) {
            Class<?> type = getTargetClass();
            if (Map.class == type) {
               return Collections.emptyMap();
            }
            else if (List.class == type) {
               return Collections.emptyList();
            }
            else if (Set.class == type || Collection.class == type) {
               return Collections.emptySet();
            }
            throw new NoSuchBeanDefinitionException(descriptor.getResolvableType(),
                  "Optional dependency not present for lazy injection point");
         }
         if (autowiredBeanNames != null) {
            for (String autowiredBeanName : autowiredBeanNames) {
               if (dlbf.containsBean(autowiredBeanName)) {
                  dlbf.registerDependentBean(autowiredBeanName, beanName);
               }
            }
         }
         return target;
      }
      @Override
      public void releaseTarget(Object target) {
      }
   };

   ProxyFactory pf = new ProxyFactory();
   pf.setTargetSource(ts);
   Class<?> dependencyType = descriptor.getDependencyType();
   if (dependencyType.isInterface()) {
      pf.addInterface(dependencyType);
   }
   return pf.getProxy(dlbf.getBeanClassLoader());
}

每次调用时会通过代理对象中的 TargetSource 再去 BeanFactory 中去发现实际的依赖对象。

image.png

image.png

更多的技术原理会在系列文章的后续内容中提供。该文章会同步在微信公众号 【DevXJava】, 方便在微信客户端阅读。


猜你喜欢

转载自blog.csdn.net/weixin_45839894/article/details/128800973