• Spring重温(三)--Spring依赖注入(DI)


    前言:在Spring框架中,DI(依赖注入)是用来定义对象彼此间的依赖,主要有set方法注入和构造器注入两种方式。另外,当一个类包含多个构造函数带的参数相同,它总是会造成构造函数注入参数类型歧义的问题,我会在第3点进行介绍并给出解决方案。

    1.setter方法注入:

    package com.yiibai.output;
    
    import com.yiibai.output.IOutputGenerator;
    
    public class OutputHelper
    {
        IOutputGenerator outputGenerator;
        
        public void setOutputGenerator(IOutputGenerator outputGenerator){
            this.outputGenerator = outputGenerator;
        }
        
    }

    一个 bean 配置文件用来声明bean 和通过 setter 设置注入(property标签)的依赖。

    <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-2.5.xsd">
    
        <bean id="OutputHelper" class="com.yiibai.output.OutputHelper">
            <property name="outputGenerator">
                <ref bean="CsvOutputGenerator" />
            </property>
        </bean>
        
    <bean id="CsvOutputGenerator" class="com.yiibai.output.impl.CsvOutputGenerator" />
    </beans>

    2.构造器注入:

    例子:

    package com.yiibai.output;
    
    import com.yiibai.output.IOutputGenerator;
    
    public class OutputHelper
    {
        IOutputGenerator outputGenerator;
        
            OutputHelper(IOutputGenerator outputGenerator){
            this.outputGenerator = outputGenerator;
        }
    }

    bean 配置文件来声明bean并通过构造函数(constructor-arg标签)设置注入依赖

    <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-2.5.xsd">
    
        <bean id="OutputHelper" class="com.yiibai.output.OutputHelper">
            <constructor-arg>
                <bean class="com.yiibai.output.impl.CsvOutputGenerator" />
            </constructor-arg>
        </bean>
        
    <bean id="CsvOutputGenerator" class="com.yiibai.output.impl.CsvOutputGenerator" />
            
    </beans>

     3.当一个类包含多个构造函数带的参数相同,它总是会造成构造函数注入参数类型歧义的问题。

     让我们来看看这个客户 bean 实例。它包含两个构造方法,均接受3个不同的数据类型参数:

    package com.yiibai.common;
    
    public class Customer 
    {
        private String name;
        private String address;
        private int age;
        
        public Customer(String name, String address, int age) {
            this.name = name;
            this.address = address;
            this.age = age;
        }
        
        public Customer(String name, int age, String address) {
            this.name = name;
            this.age = age;
            this.address = address;
        }
        //getter and setter methods
        public String toString(){
            return " name : " +name + "
     address : "
                   + address + "
     age : " + age;
        }
    
    }

    在Spring bean 的配置文件中,我们传递一个“yiibai' 的名字,地址为'188',以及年龄为'28'。

    <!--Spring-Customer.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-2.5.xsd">
    
        <bean id="CustomerBean" class="com.yiibai.common.Customer">
    
            <constructor-arg>
                <value>yiibai</value>
            </constructor-arg>
            
            <constructor-arg>
                <value>188</value>
            </constructor-arg>
            
            <constructor-arg>
                <value>28</value>
            </constructor-arg>
            </bean>
    
    </beans>

    运行它,你期望的结果是什么?

    package com.yiibai.common;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class App 
    {
        public static void main( String[] args )
        {
            ApplicationContext context = 
              new ClassPathXmlApplicationContext(new String[] {"Spring-Customer.xml"});
    
            Customer cust = (Customer)context.getBean("CustomerBean");
            System.out.println(cust);
        }
    }

    输出结果:

    name : yiibai
     address : 28
     age : 188

    其结果不是我们所期望的,第一个构造器不执行,而是第二构造函数运行。在Spring参数类型'188' 能够转换成int,所以Spring只是转换它,并采用第二个构造来执行,即使你认为它应该是一个字符串。

    另外,如果Spring不能解决使用哪个构造函数,它会提示以下错误信息
    constructor arguments specified but no matching constructor 
    found in bean 'CustomerBean' (hint: specify index and/or 
    type arguments for simple parameters to avoid type ambiguities

    为了解决这个问题,应该为构造函数指定的确切数据类型,通过像这样类型的属性:

    <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-2.5.xsd">
    
        <bean id="CustomerBean" class="com.yiibai.common.Customer">
        
            <constructor-arg type="java.lang.String">
                <value>yiibai</value>
            </constructor-arg>
            
            <constructor-arg type="java.lang.String">
                <value>188</value>
            </constructor-arg>
            
            <constructor-arg type="int">
                <value>28</value>
            </constructor-arg>
            
        </bean>
    
    </beans>

    再次运行它,现在得到你所期望的:

    name : yiibai
     address : 188
     age

    总结:在依赖注入中,主要有seter方法注入和构造函数注入两种方式,其中setter方法注入是在xml配置文件中通过property设置依赖,而构造器通过constructor-arg设置依赖;

             显式声明每个构造函数参数的数据类型,可以避免上述构造注入型歧义的问题。

  • 相关阅读:
    URL中传参带有%2F等特殊字符
    js根据对象数组中某一属性值,合并相同项,并对某一属性累加处理
    windows传输文件到linux
    npm 切换源
    linux下安装java
    PowerShell:因为在此系统上禁止运行脚本,解决方法
    wget: 未找到命令
    发货通知单禁止手工新增
    固定提前期
    容差码
  • 原文地址:https://www.cnblogs.com/hedongfei/p/7900121.html
Copyright © 2020-2023  润新知