在上篇文章中我着重介绍了Spring的控制反转和依赖注入的概念,那么依赖注入有那几种方式呢?他们的优缺点分别是什么,我将在本章中详细讲解。

Spring的依赖注入根据对象类型注入可以分为属性注入和对象注入,根据注入的方式可以分成xml配置文件注入和注解注入,其中xml有三种注入方式:

  1. 构造方法注入;
  2. setter方法注入;
  3. p名称空间注入。

注意:P名称空间为特殊的setter方法注入,因此也有人说xml有两种注入方式,本文为了详细介绍,所以分开讲解。

注解注入的方式分成三种:

  1. 构造方法注入;
  2. setter方法注入;
  3. 自动注入。

一、对象注入

1.1、xml文件注入

1.1.1、构造方法注入

public class A {private B b;private String name;public void a(){b.b();System.out.println("A中a方法执行了,name=" + name);}public A(B b, String name) {this.b = b;this.name = name;}
}
public class B {private String name;private Double age;public B(String name, Double age) {this.name = name;this.age = age;}public void b(){System.out.println("B中b方法执行了,name=" + name + ",age=" + age);}
}
    <!--创建B的Bean对象--><!--constructor-arg:构造函数赋值,注意:需要提供一个有参的构造函数有以下取值:name:构造函数所需要的参数名称value:参数名称对应的值ref:参数为其他beantype:指定参数在构造函数中的数据类型index:指定参数在构造函数中的索引位置 --><bean id="b" class="com.sxx.service.entity.B"><constructor-arg name="name" value="张三"/><constructor-arg name="age" value="12.58"/></bean><bean name="a" class="com.sxx.service.entity.A"><constructor-arg name="b" ref="b"/><constructor-arg name="name" value="王五"/></bean>
public class IocTest {public static void main(String[] args) {ApplicationContext applicationContext =new ClassPathXmlApplicationContext("bean.xml");A a = (A) applicationContext.getBean("a");a.a();}
}

B中b方法执行了,name=张三,age=12.58
A中a方法执行了,name=王五

1.1.2、set方法注入

public class A {private B b;private String name;public void a(){b.b();System.out.println("A中a方法执行了,name=" + name);}
}
public class B {private String name;private String age;public void b(){System.out.println("B中b方法执行了,name=" + name + ",age=" + age);}
}
    <!--创建B的Bean对象--><!--property:赋值属性,有以下取值:name:类中的属性值,实际找的是set方法对应的属性,比如setName -> name才能在此赋值,没有set方法会报错;value:给属性赋值,基本数据和String类型的用此种方法;ref:属性赋值是其他bean类型的--><bean id="b" class="com.sxx.service.entity.B"><property name="name" value="张三"/><property name="age" value="12"/></bean><bean name="a" class="com.sxx.service.entity.A"><property name="name" value="李四"/><!--ref指向的是上面id="b"--><property name="b" ref="b"/></bean>
public class IocTest {public static void main(String[] args) {ApplicationContext applicationContext =new ClassPathXmlApplicationContext("bean.xml");A a = (A) applicationContext.getBean("a");a.a();B b = (B) applicationContext.getBean("b");b.b();}
}

结果如下:

B中b方法执行了,name=张三,age=12.58
A中a方法执行了,name=李四
B中b方法执行了,name=张三,age=12.58

1.1.3、P名称空间注入

public class A {private B b;private String name;public void a(){b.b();System.out.println("A中a方法执行了,name=" + name);}
}
public class B {private String name;private Double age;public void b(){System.out.println("B中b方法执行了,name=" + name + ",age=" + age);}
}
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd"><bean id="a" class="com.sxx.service.entity.A"p:name="李四" p:b-ref="b"></bean><bean id="b" class="com.sxx.service.entity.B"><property name="name" value="张三"/><property name="age" value="12.58"/></bean></beans>
public class IocTest {public static void main(String[] args) {ApplicationContext applicationContext =new ClassPathXmlApplicationContext("bean.xml");A a = (A) applicationContext.getBean("a");a.a();}
}

B中b方法执行了,name=张三,age=12.58
A中a方法执行了,name=李四

1.2、注解注入

1.2.1、构造方法注入

public class A {private B b;private String name;public void a(){b.b();System.out.println("A中a方法执行了,name=" + name);}public A(B b, String name) {this.b = b;this.name = name;}
}
public class B {private String name;private Double age;public void b(){System.out.println("B中b方法执行了,name=" + name + ",age=" + age);}public B(String name, Double age) {this.name = name;this.age = age;}
}
@Configuration
public class BeanConfig {@Bean("b")//指定name=b,而非默认Bpublic B B(){return new B("张三", 12.4D);}@Beanpublic A a(){return new A(B(), "李四");}
}
<?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:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--添加spring扫描,范围是com.sxx下所有包及其子包--><context:component-scan base-package="com.sxx"/>
</beans>
public class IocTest {public static void main(String[] args) {ApplicationContext applicationContext =new ClassPathXmlApplicationContext("bean.xml");A a = (A) applicationContext.getBean("a");a.a();}
}

B中b方法执行了,name=张三,age=12.4
A中a方法执行了,name=李四

1.2.2、setter方法注入

public class A {private B b;private String name;public void a(){b.b();System.out.println("A中a方法执行了,name=" + name);}
}
public class B {private String name;private Double age;public void b(){System.out.println("B中b方法执行了,name=" + name + ",age=" + age);}
}
<!--添加spring扫描,范围是com.sxx下所有包及其子包-->
<context:component-scan base-package="com.sxx"/>
@Configuration
public class BeanConfig @Bean//如果没有指定A在Ioc容器中的key,默认为方法名public B b(){B b = new B();b.setName("张三");b.setAge(20D);return b;}@Bean//如果没有指定A在Ioc容器中的key,默认为方法名public A a(){A a = new A();//引入的是上面的b()方法a.setB(b());a.setName("李四");return a;}
}
public class IocTest {public static void main(String[] args) {ApplicationContext applicationContext =new ClassPathXmlApplicationContext("bean.xml");A a = (A) applicationContext.getBean("a");a.a();}
}

B中b方法执行了,name=张三,age=20.0
A中a方法执行了,name=李四

1.2.3、自动注入

自动注入最具代表性的就是@Resource和@Autowired两个注解,在容器中只存在单一对象的时候,两个注解功能都相同,可以相互的替换,不影响使用。

但是如果存在多个对象的时候,@Autowired只根据type进行注入,不会去匹配name。如果涉及到type无法辨别注入对象时,那需要依赖@Qualifier或@Primary注解一起来修饰。

@Resource 是JDK1.6支持的注解, 默认按照name进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名,按照名称查找。如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。

1.3、注解注入的另外一种形式

上面我们列举的注解注入的方法是通过在配置文件BeanConfig实现依赖注入的方式,还有另外一种方式可以直接在class文件中直接用@Resource或@Autowired直接引入。

1.3.1、构造方法注入

@Component
public class A {private B b;private String name;public void a(){b.b();System.out.println("A中a方法执行了,name=" + name);}@Autowiredpublic A(B b) {this.b = b;}
}
@Component
public class B {private String name;private Double age;public void b(){System.out.println("B中b方法执行了,name=" + name + ",age=" + age);}
}
 <!--添加spring扫描,范围是com.sxx下所有包及其子包--><context:component-scan base-package="com.sxx"/>
public class IocTest {public static void main(String[] args) {ApplicationContext applicationContext =new ClassPathXmlApplicationContext("bean.xml");A a = (A) applicationContext.getBean("a");a.a();}
}

B中b方法执行了,name=null,age=null
A中a方法执行了,name=null

1.3.2、setter方法注入

@Component
public class A {private B b;private String name;public void a(){b.b();System.out.println("A中a方法执行了,name=" + name);}@Autowiredpublic void setB(B b) {this.b = b;}
}

其他方法及结果参照1.3.1

1.3.3、直接注入

@Component
public class A {@Autowiredprivate B b;private String name;public void a(){b.b();System.out.println("A中a方法执行了,name=" + name);}
}

其他方法及结果参照1.3.1

二、参数注入

参数注入主要是通过@Value注入

@Component
public class A {@Autowiredprivate B b;@Value("李四")private String name;public void a(){b.b();System.out.println("A中a方法执行了,name=" + name);}
}
@Component
public class B {@Value("张三")private String name;@Value("20.4")private Double age;public void b(){System.out.println("B中b方法执行了,name=" + name + ",age=" + age);}
}

其他配置可以参照其他依赖注入的方式

结果为:

B中b方法执行了,name=张三,age=20.4
A中a方法执行了,name=李四

注意:@Value不仅可以自己配置属性还可以从配置文件或者配置中心中获取对应的属性

三、几种依赖注入的优缺点对比

3.1、构造器注入

优点:基于构造器注入,会固定依赖注入的顺序,不允许我们创建的bean对象之间存在循环依赖关系,这样Spring能解决循环依赖的问题。

缺点:使用构造器注入的缺点是,当我们构造器需要注入的对象比较多时,会显得我们的构造器,冗余,不美观,可读性差,也不易维护。

3.2、基于setter方法注入

优点:基于setter注入,只有对象是需要被注入的时候,才会注入依赖,而不是在初始化的时候就注入。

缺点:当我们选择setter方法来注入的时候,我们不能将对象设为final的;

3.3、基于自动注入

优点:在成员变量上写上注解来注入,这种方式,精短,可读性高,不需要多余的代码,也方便维护。

缺点:

1.这样不符合JavaBean的规范,而且很有可能引起空指针;

2.同时也不能将对象标为final的;

3.类与DI容器高度耦合,我们不能在外部使用它;

4.类不通过反射不能被实例化(例如单元测试中),你需要用DI容器去实例化它,这更像集成测试;

【Spring】依赖注入的几种方式相关推荐

  1. spring依赖注入的4种方式

    Spring 依赖注入的4种方式 一.Set注入 必须要有setter方法 public class UserDao {public void test(){System.out.println(&q ...

  2. spring依赖注入的三种方式以及优缺点

    spring依赖注入的三种方式以及优缺点 一.依赖注入的三种方式 1.通过构造器注入.(spring4.3之后,推荐使用) 2.通过setter注入.(spring4.3之前,推荐使用) 3通过fil ...

  3. Spring依赖注入的几种方式

    使用Spring实现依赖注入 可实现的方式有3种: 属性注入 Setter注入 构造方法注入 属性注入: 在属性声明之前添加@Autowired注解 该类必须是Spring管理对象的 public c ...

  4. spring 依赖注入的3种方式

    在实际环境中实现IoC容器的方式主要分为两大类,一类是依赖查找,依赖查找是通过资源定位,把对应的资源查找回来:另一类则是依赖注入,而Spring主要使用的是依赖注入.一般而言,依赖注入可以分为3种方式 ...

  5. Spring依赖注入的两种方式(根据实例详解)

    1,Set注入    2,构造注入 Set方法注入: 原理:通过类的setter方法完成依赖关系的设置 name属性的取值依setter方法名而定,要求这个类里面这个对应的属性必须有setter方法. ...

  6. spring依赖注入的四种方式

    平常的java开发中,程序员在某个类中需要依赖其它类的方法,则通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,spring提出了依赖注入的思想,即依赖类不由程 ...

  7. spring依赖注入有几种方式

    Spring支持两种依赖注入方式,分别是属性注入和构造函数注入.除此之外,spring还支持工厂方法注入方式. 属性注入 属性注入指通过setXxx()方法注入Bean的属性值或依赖对象.由于属性注入 ...

  8. Spring依赖注入的三种方式(好的 坏的和丑的)

    关于spring bean三种注入方式的优缺点对比,翻译自Spring DI Patterns: The Good, The Bad, and The Ugly,水平有限,如有错误请指正. Sprin ...

  9. spring 依赖注入的三种方式

    @Autowired:构造器,参数,方法,属性:都是从容器中获取参数组件的值: set方法注入: 构造器注入: 作为Bean方法的参数注入: 例子:Boss 注入Car类 第一种.set方式注入 // ...

  10. Spring系列之依赖注入的三种方式

    目录 一.依赖注入方式 1.使用属性的setXXX方法注入 2.构造函数注入 (1)按类型匹配入参type (2)按索引匹配入参index (3)联合使用类型和索引匹配入参[type和index一起使 ...

最新文章

  1. 关于write()和fsync()
  2. ICCV 2019 | Lifelong GAN:基于持续学习的条件图像生成模型
  3. flask ajax 文件上传,python flask使用ajax请求上载文件。文件为空
  4. Pycharm最新版本安装教程
  5. ls/vi等 command not found
  6. (83)FPGA时钟抖动和时钟偏斜-面试必问(七)(第17天)
  7. 柱形图无数据可选中_Excel---多层柱形图来了!让领导看呆
  8. 从菜鸟到高手!Photoshop抠图全方位攻略
  9. 使用计算机时什么是死机,电脑死机的原因是什么,电脑死机怎么办? - 电脑死机的原因 电脑死机怎么办 - 安全专题...
  10. poco库 文件服务器,poco
  11. 通过存储控制器访问外设
  12. NYOJ小明的存钱计划
  13. eclipse mars2 安装web插件
  14. c语言出错英语显示怎么看,C语言程序设计 教小学生英语 里面有代码运行错误,怎么改...
  15. React文件预览,React实现在线预览docx,xslx,pdf格式文件
  16. 毫米、微米、英寸、目数对照表
  17. Win7环境下硬盘安装XP(无光驱/光盘安装XP)
  18. 多彩M618XSD垂直立式人体工学鼠标拆解
  19. USACO-Runaround Numbers
  20. 23电工杯数学建模A题

热门文章

  1. FPGA error:buffers of the same direction cannot be placed in series.
  2. vscode配置Go支持
  3. ssh远程连接服务器
  4. VS F12键失效怎么办?
  5. [BUU刷题记录]day01-起步
  6. 【深度学习】各种卷积的理解笔记(2D,3D,1x1,可分离卷积)
  7. 图像翻译/UDA-CoCosNet v2: Full-Resolution Correspondence Learning for Image Translation图像翻译的全分辨率对应学习
  8. 数据库 mysql 删除一列数据
  9. 【自学Python】Python类型转换
  10. 解读运营指标:DAU/MAU