👉 博客主页:准Java全栈开发工程师 👉 00年出生,即将进入职场闯荡,目标赚钱,可能会有人觉得我格局小、觉得俗,但不得不承认这个世界已经不再是以一条线来分割的平面,而是围绕财富旋转的球面,成为有钱人不是为了去掌控球体的转向,而是当有人恶意掌控时,努力保护好家人和自己。


依赖注入 - setter注入、构造器注入

  • 一、依赖注入简介
  • 二、注入方式的选择
  • 三、setter注入 - 注入引用数据类型
  • 1、定义所需dao层接口及其实现类,service接口及其实现类
  • 1)BeanDao接口
  • 2)BeanDaoImpl实现类
  • 3)BeanService接口
  • 4)BeanServiceImpl实现类,该类需要依赖注入BeanDao
  • 2、applicationContext.xml文件中配置bean对象及完成依赖注入操作
  • 3、测试代码
  • 4、测试结果
  • 四、setter注入 - 注入基本数据类型
  • 1、定义所需dao层接口及其实现类
  • 1)BeanDao接口
  • 2)BeanDaoImpl实现类 - 定义了String类型的name和Integer类型的age及setter方法
  • 2、在xml文件中配置bean
  • 3、编写测试代码
  • 4、测试结果
  • 五、setter注入方式小结
  • 六、构造器注入方式 - 注入引用数据类型
  • 1、定义dao层接口及其实现类,service接口及其实现类
  • 1)BeanDao接口
  • 2)BeanDaoImpl实现类
  • 3)BeanService接口
  • 4)BeanServiceImpl实现类,该类需要依赖注入BeanDao
  • 2、在配置文件中定义bean对象并依赖注入
  • 3、编写测试代码
  • 4、测试结果
  • 七、构造器注入方式小结
  • 八、构造器注入方式的缺点及改进方式


一、依赖注入简介

  • 简单来说,依赖注入就是通过某种方式给属性赋值。
  • 依赖注入有两种方式,一种是setter注入;另一种是构造器注入。
  • 注入的数据类型有:基本数据类型和引用数据类型。

二、注入方式的选择

  • 对于强制依赖关系,可以使用构造器注入方式,因为在创建对象时一定会调用到构造器方法;而setter注入方法有较低概率不进行注入。
  • setter注入的灵活性强,对于可选的依赖关系,使用setter注入方式。
  • 但Spring框架推荐使用构造器注入方式,因为该方式更为严谨,这也是Spring框架所追求的。
  • 当然也可以同时进行构造器注入和setter方法注入。
  • 在自己开发过程中,一般情况下更推荐使用setter注入方式。原因见下文对setter注入和构造器注入的详细介绍。

三、setter注入 - 注入引用数据类型

1、定义所需dao层接口及其实现类,service接口及其实现类

1)BeanDao接口
public interface BeanDao {
    public void save();
}
2)BeanDaoImpl实现类
public class BeanDaoImpl implements BeanDao {
    public void save() {
        System.out.println("beanDao save...");
    }
}
3)BeanService接口
public interface BeanService {
    public void save();
}
4)BeanServiceImpl实现类,该类需要依赖注入BeanDao
public class BeanServiceImpl implements BeanService {
    private BeanDao beanDao;

    public void setBeanDao(BeanDao beanDao) {
        this.beanDao = beanDao;
    }

    public void save() {
        System.out.println(" bean service save...");
        beanDao.save();
    }
}

2、applicationContext.xml文件中配置bean对象及完成依赖注入操作

<bean id="beanDao" class="dao.impl.BeanDaoImpl"/>
<bean id="beanService" class="service.impl.BeanServiceImpl">
    <property name="beanDao" ref="beanDao" />
</bean>
  • 使用“property”标签来实现依赖注入操作。
  • 其中“name”属性指"BeanServiceImpl"类中指定的属性名
  • “ref”属性指定前面创建的bean对象的id属性值“beanDao"。

3、测试代码

public class App {
    public static void main(String[] args) {
        // 加载配置文件,获得上下文对象
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        BeanService beanService = (BeanService) context.getBean("beanService");
        beanService.save();
    }
}

4、测试结果

bean service save...
beanDao save...

四、setter注入 - 注入基本数据类型

1、定义所需dao层接口及其实现类

1)BeanDao接口
public interface BeanDao {
    public void save();
}
2)BeanDaoImpl实现类 - 定义了String类型的name和Integer类型的age及setter方法
public class BeanDaoImpl implements BeanDao {
    private String name;
    private Integer age;

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public void save() {
        System.out.println("beanDao save...");
        System.out.println("name : " + name + " , age : " + age);
    }
}

2、在xml文件中配置bean

<bean id="beanDao" class="dao.impl.BeanDaoImpl">
    <property name="name" value="qdxorigin"/>
    <property name="age" value="22"/>
</bean>
  • 对于引用数据类型,需要使用“ref”属性指定bean对象的id属性值。
  • 而对于基本数据类型,只需要通过“value”属性直接赋值即可。

3、编写测试代码

public class App {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        BeanDao beanDao = (BeanDao) context.getBean("beanDao");
        beanDao.save();
    }
}

4、测试结果

beanDao save...
name : qdxorigin , age : 22

注入信息能够正确输出。

五、setter注入方式小结

  • 无论是注入基本数据类型还是引用数据类型,在定义了属性之后,都需要为其定义相应的setter方法。
  • 在创建bean对象时,均是通过使用”property“标签来实现注入。
  • 引用数据类型使用”ref“属性赋值;基本数据类型使用”value“属性赋值。

六、构造器注入方式 - 注入引用数据类型

1、定义dao层接口及其实现类,service接口及其实现类

1)BeanDao接口
public interface BeanDao {
    public void save();
}
2)BeanDaoImpl实现类
public class BeanDaoImpl implements BeanDao {
    public void save() {
        System.out.println("beanDao save...");
    }
}
3)BeanService接口
public interface BeanService {
    public void save();
}
4)BeanServiceImpl实现类,该类需要依赖注入BeanDao
public class BeanServiceImpl implements BeanService {
    private BeanDao beanDao;

    public BeanServiceImpl(BeanDao beanDao) {
        this.beanDao = beanDao;
    }

    public void save() {
        System.out.println("bean service save...");
        beanDao.save();
    }
}
  • 代码和setter注入非常相似,只是将setter方法改为了构造器方法。

2、在配置文件中定义bean对象并依赖注入

<bean id="beanDao" class="dao.impl.BeanDaoImpl"/>
<bean id="beanService" class="service.impl.BeanServiceImpl">
    <constructor-arg name="beanDao" ref="beanDao"/>
</bean>
  • 细心的小伙伴已经发现了,在定义bean对象时,只是将”property“标签换成了”constructor-arg“标签,其他所有的内容都是一样的。
  • ”name“属性和”ref“属性的作用也是一样的。

3、编写测试代码

public class App {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        BeanService beanService = (BeanService) context.getBean("beanService");
        beanService.save();
    }
}

4、测试结果

bean service save...
beanDao save...

七、构造器注入方式小结

  • 其实setter注入和构造器注入两种方式的实现代码是极其相似的,只有小部分的差别。
  • 对于基本数据类型构造器注入方式的相关测试代码可以参考”setter注入 - 注入基本数据类型“相关内容,只需要把”BeanDaoImpl"类中的setter方法改为构造器方法,在xml文件注入时将“property"标签改为”constructor-arg“标签即可。

八、构造器注入方式的缺点及改进方式

  • 构造器注入方法使用的”constructor-arg“标签中的“name”属性,该属性值指定的是构造器方法中的形参名,并不是类中定义的属性名,虽然一般情况下我们会将这两个命名保持一致。这样就导致如果我们修改了构造器形参名,也需要去修改”name“属性的值,不符合低耦合的特性。

为了解决上述问题,提出了可以使用”type“属性来解决参数名耦合高的问题。

<constructor-arg type="dao.BeanDao" ref="beanDao"/>

在构造器注入时,不使用”name“属性指定具体的名字,而是改用”type"属性指定类型,通过类型匹配来完成赋值。
虽然该方式解决了参数名问题,但是如果构造器方法的形参列表中有多个相同类型的参数呢?这时应该如何完成赋值呢?谁赋值给谁又有了新的问题。

  • 使用“type”属性解决了参数名耦合问题,又出现了多个相同类型的参数赋值问题。

为了解决这个问题,又提出了使用“index”属性。

<constructor-arg index="0" ref="beanDao"/>

干脆直接使用“index”属性指定下标来进行赋值,这种方式虽然解决了相同类型参数的赋值问题,但是如果构造方法的形参列表中的参数顺序改变了呢?是不是又得来修改“index”属性的值呢?
所以,这也是为什么在“注入方式的选择”内容中,推荐使用setter方式注入的原因。

👉 以上就是文章的全部内容啦,诸佬如果有任何建议都可以提哦。