介绍
首先明确一下什么是延迟查找,一般来说通过@Autowired注解注入一个具体对象的方式是属于实时依赖查找,注入的前提是要保证对象已经被创建。而使用延迟查找的方式是我可以不注入对象的本身,而是通过注入一个代理对象,在需要用到的地方再去取其中真实的对象来使用 ,ObjectFactory提供的就是这样一种能力。
先来看一下ObjectFactory和ObjectProvider的源码
@FunctionalInterface
public interface ObjectFactory<T> {
    T getObject() throws BeansException;
}public interface ObjectProvider<T> extends ObjectFactory<T>, Iterable<T> {
    T getObject(Object... args) throws BeansException;
    
    @Nullable
    T getIfAvailable() throws BeansException;
    
    default T getIfAvailable(Supplier<T> defaultSupplier) throws BeansException {
        T dependency = getIfAvailable();
        return (dependency != null ? dependency : defaultSupplier.get());
    }
    default void ifAvailable(Consumer<T> dependencyConsumer) throws BeansException {
        T dependency = getIfAvailable();
        if (dependency != null) {
            dependencyConsumer.accept(dependency);
        }
    }
    @Nullable
    T getIfUnique() throws BeansException;
    
    default T getIfUnique(Supplier<T> defaultSupplier) throws BeansException {
        T dependency = getIfUnique();
        return (dependency != null ? dependency : defaultSupplier.get());
    }
    default void ifUnique(Consumer<T> dependencyConsumer) throws BeansException {
        T dependency = getIfUnique();
        if (dependency != null) {
            dependencyConsumer.accept(dependency);
        }
    }
    @Override
    default Iterator<T> iterator() {
        return stream().iterator();
    }
    default Stream<T> stream() {
        throw new UnsupportedOperationException("Multi element access not supported");
    }
    
    default Stream<T> orderedStream() {
        throw new UnsupportedOperationException("Ordered element access not supported");
    }
}通过源码可以看出ObjectFactory是一个顶层接口,内部只提供了直接获取对象的功能,如果对象在容器中不存则直接抛出NoSuchBeanDefinitionException异常。ObjectProvider提供了更强大的功能,支持迭代,stream 流等特性,通过getIfAvailable方法还可以避免NoSuchBeanDefinitionException 异常
用法演示
下面通过代码来演示ObjectFactory和ObjectProvider的使用方式
public class ObjectFactoryLazyLookupDemo {
    // DefaultListableBeanFactory$DependencyObjectProvider
    @Autowired
    private ObjectFactory<User> objectFactory;
    
    // DefaultListableBeanFactory$DependencyObjectProvider
    @Autowired
    private ObjectProvider<User> objectProvider;
    public static void main(String[] args) {
        // 创建应用上下文
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        
        // 注册当前类为配置类
        applicationContext.register(ObjectFactoryLazyLookupDemo.class);
        
        // 启动应用上下文
        applicationContext.refresh();
        // 获取当前类的实例
        ObjectFactoryLazyLookupDemo lazyLookupDemo = applicationContext.getBean(ObjectFactoryLazyLookupDemo.class);
        // 获取通过依赖注入的ObjectFactory和ObjectProvider对象
        ObjectFactory<User> objectFactory = lazyLookupDemo.objectFactory;
        ObjectProvider<User> objectProvider = lazyLookupDemo.objectProvider;
        // true
        System.out.println(objectFactory.getClass() == objectProvider.getClass());
        // true
        System.out.println(objectFactory.getObject() == objectProvider.getObject());
        // User{id=1, name='lazy lookup'}
        System.out.println(objectFactory.getObject());
    }
    @Bean
    private User user() {
        User user = new User();
        user.setId(1L);
        user.setName("lazy lookup");
        return user;
    }
}在上述代码中,创建了一个User对象,在注入的时候并没有直接注入对象本身,而是分别了注入了ObjectFactory<User>和ObjectProvider<User>对象,在真正使用时才通过objectFactory.getObject()去获取真实对象,在注入ObjectFactory和ObjectProvider时并没有触发依赖查找的动作,这种方式就是典型的延迟依赖查找。通过两种方式获取的User对象也是同一个对象
底层原理
在DefaultListableBeanFactory中有一个resolveDependency(DependencyDescriptor, String, Set<String>, TypeConverter) 方法,通过名称可以看出此方法专门用来解析依赖。在框架内部处理@Autowired注解时会调用此方法,方法内部会通过依赖查找的方式查出需要进行依赖注入的Bean。源码如下
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
            @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
        descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
        // 处理Optional类型的依赖注入
        if (Optional.class == descriptor.getDependencyType()) {
            return createOptionalDependency(descriptor, requestingBeanName);
        }
        // 处理ObjectFactory和ObjectProvider类型
        else if (ObjectFactory.class == descriptor.getDependencyType() ||
                ObjectProvider.class == descriptor.getDependencyType()) {
            return new DependencyObjectProvider(descriptor, requestingBeanName);
        }
        // 处理JSR330 相关的依赖注入
        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;
        }
}在代码中可以看出,如果需要进行依赖注入的Bean类型为ObjectFactory或者ObjectProvider,则直接创建一个类型为DependencyObjectProvider的实例返回。如果注入的是具体类型则代码会走最后的else分支,doResolveDependency()方法本质上就是通过依赖查找的方式去获取对应的Bean
DefaultListableBeanFactory的一个内部类,结构如下
private interface BeanObjectProvider<T> extends ObjectProvider<T>, Serializable {
}
private class DependencyObjectProvider implements BeanObjectProvider<Object> {
        private final DependencyDescriptor descriptor;
        private final boolean optional;
        @Nullable
        private final String beanName;
        public DependencyObjectProvider(DependencyDescriptor descriptor, @Nullable String beanName) {
            // 需要注入对象的类型描述,在本例中即User类型
            this.descriptor = new NestedDependencyDescriptor(descriptor);
            // 是否是Optional类型
            this.optional = (this.descriptor.getDependencyType() == Optional.class);
            // 被依赖注入的对象,本例中为objectFactoryLazyLookupDemo
            this.beanName = beanName;
        }
        @Override
        public Object getObject() throws BeansException {
            if (this.optional) {
                return createOptionalDependency(this.descriptor, this.beanName);
            }
            else {
                // 内部实际上就是通过依赖查找的方式查出所需的Bean
                Object result = doResolveDependency(this.descriptor, this.beanName, null, null);
                if (result == null) {
                    throw new NoSuchBeanDefinitionException(this.descriptor.getResolvableType());
                }
                return result;
            }
        }
        // 省略其他方法.....
    }通过代码可以看出DependencyObjectProvider实际上就是ObjectProvider类型,这里我只保留其getObject()方法,通过该方法可以看出,只有当使用者调用ObjectProvider#getObject()方法时,才会通过依赖查找的方式获取对应的Bean
总结和使用场景
通过示例代码和源码分析可以更确定延迟的概念,所谓延迟依赖查找就是等真正用到对象的时候才去获取对象。
那么使用延迟查找的应用场景有哪些呢
- 可以让依赖的资源充分等到初始化完成之后再使用
- 可以和@Lazy注解配合充分实现延迟初始化
 在本例的代码中,我们只在user()方法上面简单标注了@Bean注解,还可以通过标注@Lazy注解实现User对象的延迟初始化,和ObjectFactory配合使用就可以实现真正用到该对象的那一刻才进行初始化操作。
- 可用于解决构造器级别的循环依赖
                
 
 
                     
            
        













 
                    

 
                 
                    