一、总览
1、ObjectFactory(或ObjectProvider)可关联某一类型Bean。
2、ObjectFactory和ObjectProvider对象在被依赖注入和依赖查询时并未实时查找关联类型的Bean。
3、当ObjectFactory(或ObjectProvider)调用getObject()方法时,目标Bean才被依赖查找。
4、ObjectFactory(或ObjectProvider)相当于某一类型Bean依赖查找代理对象。
延迟查找并非是Bean的延迟加载,跟@Lazy是两码事,延迟指的就是查找的时候并没有查找到想要查找的那个bean而是查找到了,objectFactory或者objectProvider。并且Provider还比Factory多了能查找出多个的功能。ObjectProvider#getxxx 方法 底层还是通过BeanFactory来进行依赖查找的,但是在进行依赖查找前,可以制定以下规则,比如Bean找到后,再设置额外的属性,完成一些用户的自定义需求;Bean没有找到,该如何处理。
二、实例
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Lazy;
/**
* {@link ObjectFactory} 延迟依赖查找示例
* @see ObjectFactory
* @see ObjectProvider
*/
public class ObjectFactoryLazyLookupDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
// 注册 Configuration Class
context.register(ObjectFactoryLazyLookupDemo.class);
// 启动 Spring 应用上下文
context.refresh();
ObjectFactoryLazyLookupDemo objectFactoryLazyLookupDemo = context.getBean(ObjectFactoryLazyLookupDemo.class);
// userObjectFactory userObjectProvider;
// 只是拿到代理对象
ObjectFactory<User> userObjectFactory = objectFactoryLazyLookupDemo.userObjectFactory;
ObjectFactory<User> userObjectProvider = objectFactoryLazyLookupDemo.userObjectProvider;
System.out.println("userObjectFactory == userObjectProvider : " +
(userObjectFactory == userObjectProvider)); // false
System.out.println("userObjectFactory.getClass() == userObjectProvider.getClass() : " +
(userObjectFactory.getClass() == userObjectProvider.getClass())); // true
// 实际对象(延迟查找) 此时,才算是真正的查找user对象,标记了@Lazy的对象才真正开始初始化
System.out.println("user = " + userObjectFactory.getObject());
System.out.println("user = " + userObjectProvider.getObject());
System.out.println("user = " + context.getBean(User.class));
// 关闭 Spring 应用上下文
context.close();
}
@Autowired
private ObjectFactory<User> userObjectFactory;
@Autowired
private ObjectProvider<User> userObjectProvider;
@Bean
@Lazy
public static User user() {
User user = new User();
user.setId(1L);
user.setName("张三");
return user;
}
}
延迟查找并不是延迟初始化,延迟初始化还是取决于是否标记了lazy。那么这个延迟查找无论这个查找是否延迟,Bean的初始化都不由查找的时间点来单独决定,而是由标记了lazy的BeanDefinition和延迟查找两个一起来决定Bean的初始化的时间点。
以上演示的代码中,ObjectFactory和ObjectProvider并没有区别。
objectfactory设计是用来对特定bean进行加工的,比如需要进行aop代理,需要对bean个性化的时候可以用objectfactory包装一下,objectprovider一般是spring内部实现某一个功能时可能有考虑不到的地方,spring抽象一个接口类型然后通过objectprovide来进行延长查找你实现了这些接口的类,一般会设计成链式调用,我个人的理解是objectfactory用来增强bean的功能,objectprovide+特点功能扩展接口,来实现把我们的功能和spring内部逻辑整合,比如@configurationpropertys不能解析spel表达式但是spring提供了扩展接口和objectprovide功能,我通过这2个地方扩展出来使得@configurationpropertys也能像@value一样支持spel表达式(springboot2.3才支持的!)
三、原理
1、当调用ObjectFactory的getObject方法时,其实是调用了DependencyObjectProvider的getObject方法。
DependencyObjectProvider 是DefaultListableBeanFactory的内部类。
// org.springframework.beans.factory.support.DefaultListableBeanFactory.DependencyObjectProvider
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) {
this.descriptor = new NestedDependencyDescriptor(descriptor);
this.optional = (this.descriptor.getDependencyType() == Optional.class);
this.beanName = beanName;
}
@Override
public Object getObject() throws BeansException {
if (this.optional) {
return createOptionalDependency(this.descriptor, this.beanName);
}
else {
// 此时才会触发doResolveDependency
Object result = doResolveDependency(this.descriptor, this.beanName, null, null);
if (result == null) {
throw new NoSuchBeanDefinitionException(this.descriptor.getResolvableType());
}
return result;
}
}
2、调用的doResolveDependency方法,其实本质上和getBean()方法获取bean是没有差别的。