首先明确一下什么是延迟注入?
一般来说通过@Autowired注解注入一个具体对象的方式是属于实时依赖注入,注入的前提是要保证对象已经被创建。而使用延迟注入的方式是可以不注入对象的本身,而是通过注入一个代理对象,在需要用到的地方再去取其中真实的对象来使用。
实现延迟注入可以通过两种方式
@LazyObjectFactoryObjectProvider使用注解 @Lazy 的方式实现延迟注入已经很常见了(通常用来解决循环依赖注入问题),这里不再说明,今天主要说下使用 API 的方式实现延迟注入;
利用API 方式实现延迟注入 ,一个是使用 API ObjectFactory 延迟注入,另一个是使用 API ObjectProvider 延迟注入,一般情况下推荐使用 ObjectProvider ,因为其是 ObjectFactory 的拓展,在其原有基础上封装了很多便利功能。
案例:
public class LazyAnnotationDependencyInjectionDemo {
    @Autowired
    private User user; // 实时注入
    @Autowired
    private ObjectProvider<Person> userProvider; // 延迟注入
    @Autowired
    private ObjectFactory<Person> userObjectFactory; // 延迟注入
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(LazyAnnotationDependencyInjectionDemo.class);
        applicationContext.refresh();
        LazyAnnotationDependencyInjectionDemo demo = applicationContext.getBean(LazyAnnotationDependencyInjectionDemo.class);
        System.out.println("user: " + demo.user);
        // 这里并没有定义 Person 类型 Bean 对象,如果不去获取 userProvider,userObjectFactory 字段数据,就不会触发依赖注入,这里仍可以正常运行;
        // System.out.println("userProvider: " + demo.userProvider.getObject());
        // System.out.println("userObjectFactory: " + demo.userObjectFactory.getObject());
        // 按照类型依赖查找
        applicationContext.close();
    }
    @Bean
    public User user() {
        User user = new User();
        user.setId(1L);
        return user;
    }
    @Data
    static class Person {
        private String name;
        private Integer age;
    }
		@Data
    @ToString
    static class User {
        private Long id;
    }
}
如上案例, 分别使用ObjectProvider<Person>、ObjectFactory<Person> 声明userProvider、userObjectFactory 为延迟注入字段,在我们未定义 Person Bean 类型的情况下,是不影响程序正常启动的。原因可参阅 DefaultListableBeanFactory#resolveDependency 方法:

可以发现,ObjectFactory和 ObjectProvider类型的依赖在注入时,不会马上去加载真正bean,而是在使用 DependencyObjectProvider#getObject()才会触发 bean 的加载,如果无法查找到对应的 Bean 对象,就会触发 NoSuchBeanDefinitionException 异常;

               `DependencyObjectProvider#getObject()`