欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 能源 > (十二)Spring教程——依赖注入之构造函数注入

(十二)Spring教程——依赖注入之构造函数注入

2024/10/24 7:27:12 来源:https://blog.csdn.net/andy987650628/article/details/140647833  浏览:    关键词:(十二)Spring教程——依赖注入之构造函数注入

1.构造函数注入

        构造函数注入是除属性注入外的另一种常用的注入方式,它保证一些必要的属性在Bean实例化时就得到设置,确保Bean在实例化后就可以使用。

1.1按类型匹配入参

        如果任何可用的Car对象都必须提供brand和price的值,若使用属性注入方式,则只能人为地在配置时提供保证而无法在语法级提供保证,这时通过构造函数注入就可以很好地满足这一要求。使用构造函数注入的前提时Bean必须提供带参的构造函数。下面为Car提供一个可以设置brand和price属性的构造函数。

package com.example.servlet001.bean;

//默认构造函数和Setter

public class Car {

    private int maxSpeed;

    private  String brand;

    private Double price;

    public Car(String brand,double price){

        this.brand=brand;

        this.price=price;

    }

    public void setBrand(String brand){

        System.out.println("调用setBrand()设置属性。");

        this.brand=brand;

    }

    public String getBrand(){

        return this.brand;

    }

    public void setMaxSpeed(int maxSpeed){

        this.maxSpeed=maxSpeed;

    }

    public void setPrice(Double price){

        this.price=price;

    }

    public Double getPrice(){

        return this.price;

    }

}

        构造函数注入的配置方式和属性注入的配置方式有所不同,下面在Spring配置文件中使用构造函数注入的配置方式装配这个Car Bean。代码清单如下所示:
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xmlns:p="http://www.springframework.org/schema/p"

       xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="car1" name="car1" class="com.example.servlet001.bean.Car">

       <constructor-arg type="java.lang.String">

           <value>奥迪A10</value>

       </constructor-arg>

        <constructor-arg type="double">

            <value>200000</value>

        </constructor-arg>

    </bean>

</beans>

        配置文件的位置如下图所示

        添加Demo1.java测试类,类的代码如下所示

package com.example.servlet001;

import com.example.servlet001.bean.Car;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;

import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;

import org.springframework.core.io.Resource;

import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import org.springframework.core.io.support.ResourcePatternResolver;

public class Demo1 {

    public static void main(String[] args) {

        //通过xml配置文件的方式装在Bean

        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();

        Resource res = resolver.getResource("test.xml");

        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);

        reader.loadBeanDefinitions(res);

        Car car=factory.getBean("car1", Car.class);

        System.out.println("brand:"+car.getBrand());

        System.out.println("price:"+car.getPrice());

    }

}

        运行后的结果如下图所示

1.2按索引匹配入参

        我们知道Java语言通过入参的类型及顺序区分不同的重载方法。对于上面例子中的Car类,Spring仅通过type属性指定的参数类型就可以知道“奥迪A10”对应String类型的brand入参,而“200000”对应double类型的入参。但是如果Car构造函数有两个类型相同的入参,那么仅通过type就无法确定对应关系了,这时需要通过入参索引的方式进行确定。

        为了更好地演示按索引匹配入参的配置方式,我们特意对Car构造函数进行了以下调整:

package com.example.servlet001.bean;

//默认构造函数和Setter

public class Car {

    private int maxSpeed;

    private  String brand;

    private Double price;

    private String corp;//企业

    public Car(String brand,String corp,double price){

        this.brand=brand;

        this.corp=corp;

        this.price=price;

    }

    public void setBrand(String brand){

        System.out.println("调用setBrand()设置属性。");

        this.brand=brand;

    }

    public String getBrand(){

        return this.brand;

    }

    public void setMaxSpeed(int maxSpeed){

        this.maxSpeed=maxSpeed;

    }

    public void setPrice(Double price){

        this.price=price;

    }

    public Double getPrice(){

        return this.price;

    }

}

        配置文件test.xml修改为如下内容

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xmlns:p="http://www.springframework.org/schema/p"

       xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="car1" class="com.example.servlet001.bean.Car">

        <constructor-arg index="0" value="奥迪A100">

        </constructor-arg>

        <constructor-arg index="1" value="德国大众">

        </constructor-arg>

        <constructor-arg index="2" value="20000">

        </constructor-arg>

    </bean>

</beans>

        构造函数的第一个参数索引为0,第二个参数索引为1,依次类推。因此很容易知道“奥迪A100”对应brand入参,而“德国大众”对应corp入参。

        再次运行该代码后的输出结果如下图所示

 1.3联合使用类型和索引匹配入参

        有时需要type和index联合使用才能确定配置项和构造函数入参的对应关系,来看下面的例子,代码清单如下所示

package com.example.servlet001.bean;

public class Car {

    private int maxSpeed;

    private  String brand;

    private Double price;

    private String corp;//企业

    public Car(String brand,String corp,double price){

        this.brand=brand;

        this.corp=corp;

        this.price=price;

    }

    public Car(String brand,String corp,int maxSpeed){

        this.brand=brand;

        this.corp=corp;

        this.maxSpeed=maxSpeed;

    }

    public void setBrand(String brand){

        System.out.println("调用setBrand()设置属性。");

        this.brand=brand;

    }

    public String getBrand(){

        return this.brand;

    }

    public void setMaxSpeed(int maxSpeed){

        this.maxSpeed=maxSpeed;

    }

    public int getMaxSpeed(){

        return this.maxSpeed;

    }

    public void setPrice(Double price){

        this.price=price;

    }

    public Double getPrice(){

        return this.price;

    }

}

        这里,Car拥有两个重载的构造函数,它们都有三个入参,按照入参位置索引的配置方式针对这种情况又难以满足要求了,这时需要联合使用<constructor-arg>的type和index才能解决问题,配置文件的代码如下图所示

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xmlns:p="http://www.springframework.org/schema/p"

       xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="car1" class="com.example.servlet001.bean.Car">

        <constructor-arg index="0" type="java.lang.String" value="奥迪A100">

        </constructor-arg>

        <constructor-arg index="1" type="java.lang.String" value="德国大众">

        </constructor-arg>

        <constructor-arg index="2" type="int" value="400">

        </constructor-arg>

    </bean>

</beans>

        对于上述Car类中的两个构造函数,如果仅通过index进行匹配,那么Spring将无法确定第三个入参配置项究竟时对应int的maxSpeed还是double的price,所以在采用索引匹配配置时,真正引起歧义的地方是第三个入参,因此仅需要明确指定第三个入参的类型就可以消除歧义。所以在配置文件中,第一个和第二个<constructor-arg>元素的type属性可以去除。

        对于因参数数目相同而类型不同引起的潜在配置歧义问题,Spring容器可以正确启动且不会给出报错信息,它将随机采用一个匹配的构造函数实例化Bean,而被选择的构造函数可能并不是用户所期望的那个。因此,必须特别谨慎,避免潜在的错误。

1.4通过自身类型反射匹配入参

        当然,如果Bean构造函数入参的类型是可辨别的(非基础数据类型且入参类型各异),由于Java反射机制可以获取构造函数入参的类型,即使构造函数注入的配置不提供类型和索引的信息,Spring依旧可以正确地完成构造函数的注入工作。下面Boss类构造函数的入参就是可辨别的:

public Boss(String name,Car car,Office office){

  this.name=name;

  this.car=car;

  this.office=office;

}

        由于car、office和name入参的类型是可辨别的,所以无须在构造函数注入的配置时指定类型和索引,因此我们可以采用如下简易的配置方式:

<bean id="boss" class="com.example.servlet001.bean.Boss">

        <constructor-arg>

           <value>John</value>

        </constructor-arg>

        <constructor-arg>

           <ref bean=”car”>

        </constructor-arg>

        <constructor-arg>

            <ref bean=”office”>

        </constructor-arg>

    </bean>
<bean id=”car" class="com.example.servlet001.bean.Car">

<bean id="office" class="com.example.servlet001.bean.Office">

        但是为了避免潜在配置歧义引起的张冠李戴的情况,如果Bean存在多个构造函数,那么显示指定index和type属性不失为一种良好的配置习惯。

1.5循环依赖问题

        Spring容器能对构造函数配置的Bean进行实例化有一个前提,即Bean构造函数入参引用的对象必须已经准备就绪。由于这个机制的限制,如果两个Bean都采用构造函数注入,而且都通过构造函数入参引用对方,就会发生类似线程死锁的循环依赖问题。

        当启动Spring IoC容器时,因为存在循环依赖问题,Spring容器将无法成功启动。如何解决这个问题呢?用户只需要修改Bean的代码,将构造函数注入方式调整为属性注入方式就可以了。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com