第七章:Spring IoC依赖来源(Dependency Sources)

依赖查找的来源:除容器内建和自定义Spring Bean之外,还有其他来源提供依赖查找吗?

第七章:Spring IoC依赖来源(Dependency Sources)_第1张图片第七章:Spring IoC依赖来源(Dependency Sources)_第2张图片第七章:Spring IoC依赖来源(Dependency Sources)_第3张图片

依赖注入的来源:难道依赖注入的来源与依赖查找的不同吗?

第七章:Spring IoC依赖来源(Dependency Sources)_第4张图片

public class DependencySourceDemo {

    // 注入在 postProcessProperties 方法执行,早于 setter注入,也早于 @PostConstruct
    @Autowired
    private BeanFactory beanFactory;

    @Autowired
    private ResourceLoader resourceLoader;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    @PostConstruct
    public void initByInjection() {
        System.out.println("beanFactory == applicationContext " + (beanFactory == applicationContext));
        System.out.println("beanFactory == applicationContext.getBeanFactory() " + (beanFactory == applicationContext.getAutowireCapableBeanFactory()));
        System.out.println("resourceLoader == applicationContext " + (resourceLoader == applicationContext));
        System.out.println("ApplicationEventPublisher == applicationContext " + (applicationEventPublisher == applicationContext));
    }

    @PostConstruct
    public void initByLookup() {
        getBean(BeanFactory.class);
        getBean(ApplicationContext.class);
        getBean(ResourceLoader.class);
        getBean(ApplicationEventPublisher.class);
    }

    private  T getBean(Class beanType) {
        try {
            return beanFactory.getBean(beanType);
        } catch (NoSuchBeanDefinitionException e) {
            System.err.println("当前类型" + beanType.getName() + " 无法在 BeanFactory 中查找!");
        }
        return null;
    }


    public static void main(String[] args) {

        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 注册 Configuration Class(配置类) -> Spring Bean
        applicationContext.register(DependencySourceDemo.class);

        // 启动 Spring 应用上下文
        applicationContext.refresh();

        // 依赖查找 DependencySourceDemo Bean
        DependencySourceDemo demo = applicationContext.getBean(DependencySourceDemo.class);

        // 显示地关闭 Spring 应用上下文
        applicationContext.close();
    }
}

依赖查找的来源 依赖注入都支持, 而且依赖注入比依赖查找多非spring容器管理对象.

Spring IOC的三种依赖来源,自定义注册的Spring bean、内建的Spring bean以及内建的可注入的依赖,其中自定义注册的Spring bean基本上是通过xml、注解或者api注册BeanDefination创建的,内建的Spring bean是通过registerSingleton()创建的,内建的可注入的依赖是通过registerResolveDependency()创建的,后续如果我们需要往Spring容器里放入一些非Spring托管的bean但又可以被依赖注入的, 可以通过registerResolveDependency() API实现

Spring容器管理和游离对象:为什么会有管理对象和游离对象?

第七章:Spring IoC依赖来源(Dependency Sources)_第5张图片
单体对象就是已初始化的外部 Java 对象,在 Spring 容器中是唯一的

单体对象是最普通的 Spring IoC 中使用的对象,而游离对象主要是类似 scope 为 prototype 这样的获取对象。

Spring Bean Definition作为依赖来源:Spring Bean的来源

第七章:Spring IoC依赖来源(Dependency Sources)_第6张图片

单例对象作为依赖来源:单体对象与普通Spring Bean存在哪些差异?

第七章:Spring IoC依赖来源(Dependency Sources)_第7张图片
为什么说单例对象无法实现延迟初始化bean,不是有lazy么?
因为单体对象是外部已初始化对象,所以不存在 Lazy 的问题,Lazy 针对于 BeanDefinition,而非具体对象。

非Spring容器管理对象作为依赖来源:如何理解ResolvableDependency?

第七章:Spring IoC依赖来源(Dependency Sources)_第8张图片

public class ResolvableDependencySourceDemo {

    @Autowired
    private String value;

    @PostConstruct
    public void init() {
        System.out.println(value);
    }

    public static void main(String[] args) {

        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();

        // 注册 Configuration Class(配置类) -> Spring Bean
        applicationContext.register(ResolvableDependencySourceDemo.class);

        applicationContext.addBeanFactoryPostProcessor(beanFactory -> {
            // 注册 Resolvable Dependency
            beanFactory.registerResolvableDependency(String.class, "Hello,World");
        });

        // 启动 Spring 应用上下文
        applicationContext.refresh();

        // 显示地关闭 Spring 应用上下文
        applicationContext.close();
    }

}

总结:注册非spring管理的依赖对象时,可以通过两种方式实现
1.通过ApplicationContext.getBeanFactory()获取AnnotationConfigApplicationContext创建时初始化的DefaultListableBeanFactory对象,然后调用registryResolveableDependency来注册,为啥不能通过getAutowireCapableBeanFactory()来获取beanFactory对象,因为方法中需要beanFactory已被激活即执行了ApplicationContext的refresh()操作之后
2.通过addBeanFactoryPostProcessor回调方式实现,因为当refresh()方法执行invokeBeanFactoryPostProcessors()时会遍历已创建的beanFactoryPostProcessors集合对象来执行postProcessBeanFactory()方法

annotationConfigApplicationContext.getAutowireCapableBeanFactory();这种方式,会调用assertBeanFactoryActive(),验证BeanFactory;使用annotationConfigApplicationContext.getBeanFactory();就不会报错,
因为没有验证环节 所以这样也是可以的
ConfigurableListableBeanFactory beanFactory = annotationConfigApplicationContext.getBeanFactory();

     beanFactory.registerResolvableDependency(String.class,"hello world");
    annotationConfigApplicationContext.register(ResolvableDependencySourceDemo.class);
    annotationConfigApplicationContext.refresh();

外部化配置作为依赖来源:@Value是如何将外部化配置注入Spring Bean的?

第七章:Spring IoC依赖来源(Dependency Sources)_第9张图片

@Configuration
@PropertySource(value = "META-INF/default.properties",encoding="UTF-8")
public class ExternalConfigurationDependencySourceDemo {

    @Value("${user.id:-1}")
    private Long id;

    @Value("${usr.name}")
    private String name;

    @Value("${user.resource:classpath://default.properties}")
    private Resource resource;

    public static void main(String[] args) {

        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 注册 Configuration Class(配置类) -> Spring Bean
        applicationContext.register(ExternalConfigurationDependencySourceDemo.class);

        // 启动 Spring 应用上下文
        applicationContext.refresh();

        // 依赖查找 ExternalConfigurationDependencySourceDemo Bean
        ExternalConfigurationDependencySourceDemo demo = applicationContext.getBean(ExternalConfigurationDependencySourceDemo.class);

        System.out.println("demo.id = " + demo.id);
        System.out.println("demo.name = " + demo.name);
        System.out.println("demo.resource = " + demo.resource);

        // 显示地关闭 Spring 应用上下文
        applicationContext.close();
    }
}

通过@Value属性读取通过@PropertySource所关联的文件,若有字符集设置可通过@PropertySource中encoding设置

面试题

第七章:Spring IoC依赖来源(Dependency Sources)_第10张图片
第七章:Spring IoC依赖来源(Dependency Sources)_第11张图片
不过 Spring IoC 最大特性是 DI,所以启动 ApplicationContext 后,再注册并查找 Bean 价值不大了~第七章:Spring IoC依赖来源(Dependency Sources)_第12张图片

你可能感兴趣的:(Spring核心编程思想)