• x-ray
    2021-01-09
    延迟查找,我个人认为主要是给架构开发者使用的。非常典型的一个使用场景,就是SpringBoot里的自动配置,可以看看LettuceConnectionConfiguration这个类,这个类用于创建RedisClient。显然,RedisClient的创建是要根据用户的需求来创建的。 有些属性是必须的,可以在配置文件里配置,比如ip,port这种。Lettuce在创建RedisClient的时候,会从配置文件里读取这些数据来创建RedisClient。 但有些属性是非必须的,而且不能在配置文件里配置,比如开启读写分离,RedisClient在Lettuce内部,是通过一个Builder来创建的,如果要开启读写分离,这需要你在这个Builder在执行build的过程中,额外加一行:clientConfigurationBuilder.readFrom(ReadFrom.REPLICA); 问题就在这里,怎么让业务开发人员把这行代码加入到其内部的build流程中?这个问题,一种比较常见的思路,是使用模板方法,写一个抽象方法,调用它。具体的实现交给开发人员。 所以Lettuce设计了一个LettuceClientConfigurationBuilderCustomizer的类,他有一个customize方法,并且把上面提到的Builder作为这个方法的参数传递进来。开发人员,如果能去配置LettuceClientConfigurationBuilderCustomizer这样一个类,就能达到上述的目的。 但问题是,如果是开发人员去配置这样一个类,说明LettuceClientConfigurationBuilderCustomizer这个类还没有被实例化。但根据模板模式,流程中必须调用LettuceClientConfigurationBuilderCustomizer这个类的抽象方法,才能达到目的。 这个时候延迟加载,ObjectProvider的作用就体现出来了。他可以规定,他产生的是一个LettuceClientConfigurationBuilderCustomizer的对象,并且指定这个对象产生以后,做什么事情。比如调用customize方法。 如果用户配置了LettuceClientConfigurationBuilderCustomizer对象。那么在创建RedisClient的流程中,ObjectProvider就能拿到该对象,然后按照预先指定的动作执行,比如执行customize方法。 如果用户没配置,那么拿不到Bean对象,就什么都不做。 所以这个场景,我认为是延迟查找的一个典型实现
    展开

    作者回复: 是的,类似于 Spring Boot 和 Spring Cloud 时常出现

    共 3 条评论
    22
  • 周治慧
    2020-03-05
    没太明白这一节的延迟查找体现在哪里,在@Lazy注解的时候当一个普通bean中有属性是@Lazy修饰的bean对象时可以通过这个bean对象是否存在后不存在不影响普通bean的注册发现,通过ObjectProvider时没明白咋回事

    作者回复: ObjectProvider 是间接的依赖查找,ObjectProvider 相当于一个代理,实际依赖查找发生在ObjectProvider#get 等方法时。

    共 2 条评论
    10
  • 地平线
    2021-01-27
    延迟查找并非是Bean的延迟加载,跟@Lazy是两码事,ObjectProvider#getxxx 方法 底层还是通过BeanFactory来进行依赖查找的,但是在进行依赖查找前,可以制定以下规则,比如Bean找到后,再设置额外的属性,完成一些用户的自定义需求;Bean没有找到,该如何处理

    作者回复: 理解正确~

    共 2 条评论
    4
  • x-ray
    2021-01-09
    再补充一下,我个人认为,延迟的关键意义在于,提前预定义延迟对象将来的一系列行为事件(实际上该对象尚未被实例化)。通过预设的方式,事先规定好该对象要做些什么。而对象本身交由使用者去定义它的创建内容,从而实现,在固定流程下进行个性化配置,这样一个目的。

    作者回复: 学习课代表~

    共 3 条评论
    4
  • 甘乐
    2020-03-12
    感觉这一节并没有很突出"延迟"这个概念, 小马哥可能想表达 当我们通过 beanFactory的getObjectProvider,获取这个ObjectProvider对象的时候,我们可以通过ObjectProvider的getIfAvailable()方法来查找(如不存在则创建) 来实现延迟加载Bean?

    作者回复: ObjectProvider 对象获取时,并没有获取实际 Bean 的对象,而是在 getObject() 或其他获取方法时才获取

    共 2 条评论
    4
  • 大大大熊myeh
    2020-02-28
    这一小节讲的是延迟查找,通过ObjectProvider接口实现,是不是可以突显一下“延迟”的意义或者表现形式,因为我看下来,不是特别理解延迟的意义。。。

    作者回复: 主要是凸显延迟的形式,这个实例可能不是特别典型~

    
    3
  • 水滴s
    2020-04-25
    我是通过xml注册的: <bean id="aUser" class="org.example.springdemo.pojo.User"> <property name="id" value="1"/> <property name="name" value="www"/> </bean> // java 代码 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(); context.setConfigLocation("xml-config/spring-instance.xml"); context.refresh(); User bean1 = context.getBean(User.class); User bean2 = context.getBean(User.class, "www2"); 这样做发现 这两个方法返回的一样 org.springframework.beans.factory.BeanFactory#getBean(java.lang.Class<T>, java.lang.Object...) 这个方法根据 类型 和 覆盖构造器参数查找,没起作用
    展开

    作者回复: 实际上你的例子存在一定问题,例子中的 BeanDefinition 确定了,您看看我的例子: public class GetBeanDemo { public static void main(String[] args) { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); BeanDefinition beanDefinition = genericBeanDefinition(User.class) .setAutowireMode(AUTOWIRE_CONSTRUCTOR) .getBeanDefinition(); beanFactory.registerBeanDefinition("user",beanDefinition); User user = beanFactory.getBean("user",User.class,"mercyblitz"); System.out.println(user); } static class User { private final String name; public User(String name) { this.name = name; } @Override ublic String toString() { return "User{" + "name='" + name + '\'' + '}'; } } }

    
    2
  • 刘彬
    2021-04-25
    跟代码的时候发现一个强大的工具类ResolvableType,顺便也学习了一下泛型反射

    作者回复: 在后面泛型章节中,会详细讨论~

    
    1
  • 码小呆
    2021-04-15
    延迟查找是不是可以解决 spring 循环依赖的问题呢?

    作者回复: 可以解决 Spring 构造注入时循环依赖的问题

    
    1
  • 王娜
    2021-01-30
    小马哥,有个问题请教你,代码如下 @Component public class Teacher { private Student student; public Student getStudent() { return student; } public void setStudent(ObjectProvider<Student> studentObjectProvider) { this.student = studentObjectProvider.getIfAvailable(Student::new); } } @Component public class Student { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } @ComponentScan(basePackages = "my.practise") public class ObjectProviderPractise { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); applicationContext.register(ObjectProviderPractise.class); applicationContext.refresh(); Student student = applicationContext.getBean(Student.class); student.setName("yang"); System.out.println("Set Student Name:"+ student.getName()); Teacher teacher = applicationContext.getBean(Teacher.class); System.out.println(teacher); System.out.println("student name:" + teacher.getStudent().getName()); applicationContext.close(); } } 据说4.3之后下面这里不用写@Autowired也能完成注入,但是我测出来不行,teacher.getStudent().getName()报空指针异常,麻烦看看是怎么回事? public void setStudent(ObjectProvider<Student> studentObjectProvider) { this.student = studentObjectProvider.getIfAvailable(); }
    展开

    作者回复: 这里可能有点误会,当 @Bean 方法定义时,@Autowired 不需要注解标注,而 @Component Class 时则需要。

    共 2 条评论
    1