• 【Spring】IoC容器


    前言

    上一篇文章已经学习了【依赖注入】相关的知识,这里详细的介绍一下【依赖来源】。

    依赖来源

    我们把依赖来源分为依赖查找的来源和依赖注入的来源分别讨论。

    依赖查找的来源

    1. Spring BeanDefinition

    这里的Spring BeanDefinition又可以细分为:

    • 1.1 客户端自建的Spring Bean:
      如 UserService等等bean
    • 1.2 Spring容器启动时辅助的bean,可以称为Spring内建bean:
      如 org.springframework.context.annotation.internalAutowiredAnnotationProcessor
      这里的Spring内建bean是在AnnotationConfigUtils.registerAnnotationConfigProcessors()静态方法中所注册的,即注册到BeanDefinitionMap中。
    点击查看[源码片段]
    	public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
    			BeanDefinitionRegistry registry, @Nullable Object source) {
                //省略。。。
    		if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    			RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
    			def.setSource(source);
    			beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
    		}
                //省略。。。
    	}
    

    2. 单例对象

    单例对象是指Spring容器启动时创建的一些单例bean,如容器中的Environment对象:
    这里的Spring内建bean是在AbstractApplicationContext.prepareBeanFactory()中,添加到BeanFactory的。

    点击查看[源码片段]
    	protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
                    //省略...
    		// Register default environment beans.
    		if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
    			beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
    		}
                    //省略...
    	}
    

    其中1.2【Spring内建bean】以及2【单例对象】中的Spring内建bean都是在 依赖查找 章节中介绍的【Spring内建依赖】中的依赖。

    依赖注入的来源

    1. Spring BeanDefinition

    同上述【依赖查找的来源】。

    2. 单例对象

    同上述【依赖查找的来源】。

    3. 非Spring容器管理对象(ResolvableDependency、非推广对象、游离对象)

    这里的【非Spring容器管理对象】是在单例对象那个方法里面一起注册的:
    AbstractApplicationContext.prepareBeanFactory()中:

    点击查看[源码片段]
    	protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
                    //省略...
    		// BeanFactory interface not registered as resolvable type in a plain factory.
    		// MessageSource registered (and found for autowiring) as a bean.
    		beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
    		beanFactory.registerResolvableDependency(ResourceLoader.class, this);
    		beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
    		beanFactory.registerResolvableDependency(ApplicationContext.class, this);
                    //省略...
    	}
    

    那这几个游离对象是怎么运用的呢?
    在上一章依赖注入章节中的源码分析中,我们知道在解析注入的依赖的时候:有一个方法DefaultListableBeanFactory.doResolveDependency
    在该方法中,调用了:DefaultListableBeanFactory.findAutowireCandidates(),内部会处理我们这4个特殊的游离对象的注入。
    这也就是为什么Spring框架中,我们可以直接用如下代码注入BeanFactory或者ApplicationContext:

    @Autowired
    ApplicationContext applicationContext;
    

    4. 外部化配置

    因为到此为止还没有系统整理以及学习到外部化配置章节,并且基于学习者都是有spring基础的前提下,下例默认在META-INF/default.properties中拥有部分配置。

    点击查看[示例代码]
    @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();
        }
    }
    

    依赖查找的来源 VS 依赖注入的来源

    点击查看[示例代码]
    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> T getBean(Class<T> 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();
        }
    

    运行结果:

    beanFactory == applicationContext false
    beanFactory == applicationContext.getBeanFactory() true
    resourceLoader == applicationContext true
    ApplicationEventPublisher == applicationContext true
    当前类型org.springframework.beans.factory.BeanFactory 无法在 BeanFactory 中查找!
    当前类型org.springframework.context.ApplicationContext 无法在 BeanFactory 中查找!
    当前类型org.springframework.core.io.ResourceLoader 无法在 BeanFactory 中查找!
    当前类型org.springframework.context.ApplicationEventPublisher 无法在 BeanFactory 中查找!
    

    这里补充一下上图缺少的[外部化配置]的特点:

    类型:非常规的Spring对象依赖来源
    有无生命周期管理:无
    能否延迟初始化:不能
    能否依赖查找:不能

    Spring BeanDefinition 注册的源码位置

    BeanDefinitionRegistry
    DefaultListableBeanFactory#registerBeanDefinition
    BeanDefinitionBuilder

    单例对象注册到Spring IOC 容器的过程 以及 在依赖查找过程中的所充当的角色

    单例对象注册到Spring IOC 容器的过程
    SingletonBeanRegistry
    DefaultListableBeanFactory#registerSingleton

    在依赖查找过程中的所充当的角色:
    AbstractBeanFactory#getBean(java.lang.String)

    非Spring容器管理对象的应用

    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,必须在refresh()方法之后执行,但是又必须在aitowired(bean初始化)之前执行
                beanFactory.registerResolvableDependency(String.class, "Hello,World");
            });
    
            // 启动 Spring 应用上下文
            applicationContext.refresh();
    
            // 显示地关闭 Spring 应用上下文
            applicationContext.close();
        }
    }
    

    注:游离对象可以被应用人员随意注册到spring中,但是需要保证游离对象只能被依赖注入,不能被依赖查找。

    外部化配置在spring启动过程中的源码位置

    org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
    org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency

    DefaultListableBeanFactory#doResolveDependency源码片段

                            //下面的type在上例中第一个获取到java.lang.Long
    			Class<?> type = descriptor.getDependencyType();
                            //下面的getAutowireCandidateResolver()方法会得到一个ContextAnnotationAutowireCandidateResolver解析类
                            //该解析类会在下面的getSuggestedValue()方法中解析value的值,此时还是占位符
    			Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
    			if (value != null) {
    				if (value instanceof String) {
                                            //这里会把@Value注解的默认值解析出来
    					String strVal = resolveEmbeddedValue((String) value);
    

    ContextAnnotationAutowireCandidateResolver.super.getSuggestedValue(DependencyDescriptor descriptor)源码:

    	public Object getSuggestedValue(DependencyDescriptor descriptor) {
    		Object value = findValue(descriptor.getAnnotations());
    		if (value == null) {
    			MethodParameter methodParam = descriptor.getMethodParameter();
    			if (methodParam != null) {
    				value = findValue(methodParam.getMethodAnnotations());
    			}
    		}
    		return value;
    	}
    
  • 相关阅读:
    DB2 for Z/os Statement prepare
    Foreign key (referential) constraints on DB2 LUW v105
    复制Informational constraints on LUW DB2 v105
    DB2 SQL Mixed data in character strings
    DB2 create partitioned table
    MVC中使用EF的技巧集(一)
    Asp.Net MVC 开发技巧(二)
    Linq使用技巧及查询示例(一)
    Asp.Net MVC 开发技巧(一)
    Asp.Net MVC Identity 2.2.1 使用技巧(八)
  • 原文地址:https://www.cnblogs.com/1626ace/p/15349612.html
Copyright © 2020-2023  润新知