zoukankan      html  css  js  c++  java
  • Spring IOC(五)依赖注入

    Spring IOC(五)依赖注入

    Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html)

    一、autowire 五种注入方式测试

    (1) 环境准备

    public class Company {
        private Department department;
        private List<Employee> employees;
    
        public Company() {
        }
        public Company(Department department) {
            this.department = department;
        }
        public void setDepartment(Department department) {
            this.department = department;
        }
        public void setEmployees(List<Employee> employees) {
            this.employees = employees;
        }
    }
    
    public class Employee {
        private String name;
        public void setName(String name) {
            this.name = name;
        }
    }
    
    public class Department {
        private String name;
        public void setName(String name) {
            this.name = name;
        }
    }
    

    (2) xml 配置

    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="company1" autowire="byName" class="com.github.binarylei.Company"/>
        <bean id="company2" autowire="byType" class="com.github.binarylei.Company"/>
        <bean id="company3" autowire="no" class="com.github.binarylei.Company"/>
        <bean id="company4" autowire="constructor" class="com.github.binarylei.Company">
            <constructor-arg index="0" ref="department"/>
        </bean>
        <bean id="company5" autowire="default" class="com.github.binarylei.Company"/>
    
        <bean id="employee1" class="com.github.binarylei.spring.Employee">
            <property name="name" value="employee1"/>
        </bean>
        <bean id="employee2" class="com.github.binarylei.spring.Employee">
            <property name="name" value="employee2"/>
        </bean>
    
        <bean id="department" class="com.github.binarylei.spring.Department">
            <property name="name" value="department"/>
        </bean>
    </beans>
    

    (3) 测试一把

    @Test
    public void test() {
        DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(lbf);
        reader.loadBeanDefinitions(new ClassPathResource("spring-context-di.xml", getClass()));
    
        // 1. 名称注入
        Company companyByName = (Company) lbf.getBean("company1");
        // 2. 类型注入,支持 List 方式注入,如果本地容器找到多个则直接抛出异常
        Company companyByType = (Company) lbf.getBean("company2");
        // 3. no
        Company companyByNo = (Company) lbf.getBean("company3");
        // 4. 构造器注入
        Company companyByConstructor = (Company) lbf.getBean("company4");
        // 5. 默认
        Company companyDefault = (Company) lbf.getBean("company5");
    }
    

    二、Spring 属性注入源码分析

    2.1 属性注入 - populateBean

    Spring 属性注入在 populateBean 方法中完成,有两种注入方式:beanName 或 type 两种。

    protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    	if (bw == null) {
    		if (mbd.hasPropertyValues()) {
    			throw new BeanCreationException("Cannot apply property values to null instance");
    		} else {
    			return;
    		}
    	}
    
    	// 1. 后置处理器 InstantiationAwareBeanPostProcessor,可以先略过
    	boolean continueWithPropertyPopulation = true;
    	if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
    		for (BeanPostProcessor bp : getBeanPostProcessors()) {
    			if (bp instanceof InstantiationAwareBeanPostProcessor) {
    				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
    				if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
    					continueWithPropertyPopulation = false;
    					break;
    				}
    			}
    		}
    	}
    	if (!continueWithPropertyPopulation) {
    		return;
    	}
    
    	// 2. 依赖查找。根据 beanName 或 type 查找可注入的属性值。
    	PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
    	if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
    		MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
    		if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
    			autowireByName(beanName, mbd, bw, newPvs);
    		}
    		if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
    			autowireByType(beanName, mbd, bw, newPvs);
    		}
    		pvs = newPvs;
    	}
    
    	boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    	boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
    
    	// 3. 后置处理器拦截,对属性值进行处理 InstantiationAwareBeanPostProcessor
    	PropertyDescriptor[] filteredPds = null;
    	if (hasInstAwareBpps) {
    		if (pvs == null) {
    			pvs = mbd.getPropertyValues();
    		}
    		for (BeanPostProcessor bp : getBeanPostProcessors()) {
    			if (bp instanceof InstantiationAwareBeanPostProcessor) {
    				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
    				PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
    				if (pvsToUse == null) {
    					if (filteredPds == null) {
    						filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
    					}
    					pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
    					if (pvsToUse == null) {
    						return;
    					}
    				}
    				pvs = pvsToUse;
    			}
    		}
    	}
    
    	// 4. 依赖校验。是否所有的字段已经全部匹配上了,根据需要是否要抛出异常
    	if (needsDepCheck) {
    		if (filteredPds == null) {
    			// 过滤不需要进行属性注入的字段,如 String、BeanFactory...
    			filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
    		}
    		checkDependencies(beanName, mbd, filteredPds, pvs);
    	}
    
    	// 5. 依赖注入。至些属性已经全部准备好了,可以进行属性注入。
    	if (pvs != null) {
    		applyPropertyValues(beanName, mbd, bw, pvs);
    	}
    }
    

    上面的代码看这很复杂,其实抛开后置处理器 InstantiationAwareBeanPostProcessor 就做了三件事,其中属性的查找,尤其是根据类型的查找最为复杂:

    1. 依赖查找。根据 beanName 或 type 查找可注入的依赖值。
    2. 依赖校验。是否所有的字段已经全部匹配上了,根据需要是否要抛出异常
    3. 依赖注入。至些依赖已经全部准备好了,可以进行属性注入。

    参考:

    1 . 《Spring各种依赖注入注解的区别》:https://blog.csdn.net/gaohe7091/article/details/39319363


    每天用心记录一点点。内容也许不重要,但习惯很重要!

  • 相关阅读:
    bloom(转)
    关于模态对话框某些情况下在opengl下需要按alt才能显示的问题
    程序员的特征
    ffmpeg cross compile
    Tone mapping
    osgXI
    dx11 about post process...
    asp.net网站异常处理方式
    把datatable导出到指定的excel中
    Visual Studio 2008功能提升
  • 原文地址:https://www.cnblogs.com/binarylei/p/10340112.html
Copyright © 2011-2022 走看看