(4)Spring框架----依赖注入(DI)
Spring发展到现在遵循“约定大于配置”原则,在基本的应用配置上(如数据库配置),建议采用XML配置方式;在业务逻辑处理上,建议采用注解方式。回顾过往,XML配置方式真的让人又爱又恨。所以,本节通篇采用XML配置方式。
1.DI的配置使用
1.1 依赖和依赖注入
传统应用程序设计中所说的依赖一般指“类之间的关系”,那先让我们复习一下类之间的关系:
- 泛化:表示类与类之间的继承关系、接口与接口之间的继承关系;
- 实现:表示类对接口的实现;
- 依赖:当类与类之间有使用关系时就属于依赖关系,不同于关联关系,依赖不具有“拥有关系”,而是一种“相识关系”,只在某个特定地方(比如某个方法体内)才有关系。
- 关联:表示类与类或类与接口之间的依赖关系,表现为“拥有关系”;具体到代码可以用实例变量来表示;
- 聚合:属于是关联的特殊情况,体现部分-整体关系,是一种弱拥有关系;整体和部分可以有不一样的生命周期;是一种弱关联;
- 组合:属于是关联的特殊情况,也体现了体现部分-整体关系,是一种强“拥有关系”;整体与部分有相同的生命周期,是一种强关联;
1.2 IoC容器依赖的含义
Spring IoC容器的依赖有两层含义:Bean依赖容器和容器注入Bean的依赖资源:
- Bean依赖容器:也就是说Bean要依赖于容器,这里的依赖是指容器负责创建Bean并管理Bean的生命周期,正是由于由容器来控制创建Bean并注入依赖,也就是控制权被反转了,这也正是IoC名字的由来,此处的有依赖是指Bean和容器之间的依赖关系。
- 容器注入Bean的依赖资源:容器负责注入Bean的依赖资源,依赖资源可以是Bean、外部文件、常量数据等,在Java中都反映为对象,并且由容器负责组装Bean之间的依赖关系,此处的依赖是指Bean之间的依赖关系,可以认为是传统类与类之间的“关联”、“聚合”、“组合”关系。
1.3 依赖注入的好处
为什么要应用依赖注入,应用依赖注入能给我们带来哪些好处呢?
- 动态替换Bean依赖对象,程序更灵活:替换Bean依赖对象,无需修改源文件:应用依赖注入后,由于可以采用配置文件方式实现,从而能随时动态的替换Bean的依赖对象,无需修改java源文件;
- 更好实践面向接口编程,代码更清晰:在Bean中只需指定依赖对象的接口,接口定义依赖对象完成的功能,通过容器注入依赖实现;
- 更好实践优先使用对象组合,而不是类继承:因为IoC容器采用注入依赖,也就是组合对象,从而更好的实践对象组合。
采用对象组合,Bean的功能可能由几个依赖Bean的功能组合而成,其Bean本身可能只提供少许功能或根本无任何功能,全部委托给依赖Bean,对象组合具有动态性,能更方便的替换掉依赖Bean,从而改变Bean功能;
而如果采用类继承,Bean没有依赖Bean,而是采用继承方式添加新功能,,而且功能是在编译时就确定了,不具有动态性,而且采用类继承导致Bean与子Bean之间高度耦合,难以复用。
- 增加Bean可复用性:依赖于对象组合,Bean更可复用且复用更简单;
- 降低Bean之间耦合:由于我们完全采用面向接口编程,在代码中没有直接引用Bean依赖实现,全部引用接口,而且不会出现显示的创建依赖对象代码,而且这些依赖是由容器来注入,很容易替换依赖实现类,从而降低Bean与依赖之间耦合;
- 代码结构更清晰:要应用依赖注入,代码结构要按照规约方式进行书写,从而更好的应用一些最佳实践,因此代码结构更清晰。
由此可以看出,其实依赖注入只是一种装配对象的手段,设计的类结构才是基础,如果设计的类结构不支持依赖注入,Spring IoC容器也注入不了任何东西,从而从根本上说“如何设计好类结构才是关键,依赖注入只是一种装配对象手段”。
2.依赖注入实现方式
前边IoC一章我们已经了解了Bean依赖容器,那容器如何注入Bean的依赖资源,Spring IoC容器注入依赖资源主要有以下两种基本实现方式:
- 构造器注入:就是容器实例化Bean时注入那些依赖,通过在在Bean定义中指定构造器参数进行注入依赖,包括实例工厂方法参数注入依赖,但静态工厂方法参数不允许注入依赖;
- setter注入:通过setter方法进行注入依赖;
- 接口注入:
我们已经知道注入实现方式了,接下来让我们来看看具体配置吧。
2.1 构造方法注入
先定义一个汽车类
/*** 依赖注入* 【1】构造方法的注入方式*/
public class Car {private String name;private Double price;public Car(String name, Double price) {this.name = name;this.price = price;}@Overridepublic String toString() {return "Car [name=" + name + ", price=" + price + "]";}}
XML配置:
<!-- ========================依赖注入注入的几种方式========================== -->
<!-- ========================1.使用构造方法的方式注入======================== -->
<!-- 常规构造方法注入 -->
<bean id="car" class="com.hl.spring.ioc.charcater4.Car" >
<!-- <constructor-arg name="name" value="大奔"/><constructor-arg name="price" value="100000"/>
--><constructor-arg index="0" value="奇瑞QQ"/><constructor-arg index="1" value="20000"/>
</bean>
汽车出来,总得有人去开车,造个人出来吧,Person类:
public class Person {private String name;private Car car;public Person(String name, Car car) {super();this.name = name;this.car = car;}@Overridepublic String toString() {return "Person [name=" + name + ", car=" + car + "]";}
}
XML配置文件:
<!-- 构造方法注入,当Java类的属性是另一个Java类时 -->
<bean id="person" class="com.hl.spring.ioc.charcater4.Person"><constructor-arg name="name" value="xiaoming"/><constructor-arg name="car" ref="car"/>
</bean>
2.2 set方法注入
/*** 依赖注入* 【2】set方法的注入方式*/
public class Car2 {private String name;private Double price;public String getName() {return name;}public void setName(String name) {this.name = name;}public Double getPrice() {return price;}public void setPrice(Double price) {this.price = price;}@Overridepublic String toString() {return "Car [name=" + name + ", price=" + price + "]";}
}
XML配置:
<!-- ==========================2.使用Set方法的方式注入========================== -->
<bean id="car2" class="com.hl.spring.ioc.charcater4.Car2"><property name="name" value="赛特"/><property name="price" value="998" />
</bean>
3. 测试
测试类:
public class Test01 {@Testpublic void run(){ApplicationContext context = new ClassPathXmlApplicationContext("/character4.xml");/*【1】构造方法注入*/Car c = context.getBean("car",Car.class);System.out.println("构造方法注入:" + c);/*【1】构造方法注入,Java类的属性是另一个Java类时*/Person person = context.getBean("person",Person.class);System.out.println("构造方法注入:" + person);/*【2】set方法注入*/Car2 car2 = context.getBean("car2",Car2.class);System.out.println("set方法注入:" + car2);}
}
测试结果:
构造方法注入:Car [name=奇瑞QQ, price=2000.0]
构造方法注入:Person [name=xiaoming, car=Car [name=奇瑞QQ, price=2000.0]]
set方法注入:Car [name=赛特, price=998.0]
4. 注入复杂类型
Spring不仅能注入简单类型数据,还能注入集合(Collection、无序集合Set、有序集合List)类型、数组(Array)类型、字典(Map)类型数据、Properties类型数据,接下来就让我们一个个看看如何注入这些数据类型的数据。
/*** 复杂类型的注入*/
public class CollectionBean {private String[] arrs;private List<String> list;private Set<String> set;private Map<String, Integer> map;private Properties properties;public void setArrs(String[] arrs) {this.arrs = arrs;}public void setSet(Set<String> set) {this.set = set;}public void setMap(Map<String, Integer> map) {this.map = map;}public void setProperties(Properties properties) {this.properties = properties;}public void setList(List<String> list) {this.list = list;}@Overridepublic String toString() {return "CollectionBean [arrs=" + Arrays.toString(arrs) + ", list=" + list + ", set=" + set + ", map=" + map+ ", properties=" + properties + "]";}
}
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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- ===================依赖注入注入,注入复杂类型=========================== --><!-- properties标签中的name名称需要与CollectionBean类中对应变量的名称一致 --><bean id="collectionBean" class="com.hl.spring.ioc.charcater5.CollectionBean"><!-- ========================注入数组======================== --><property name="arrs"><list><value>哈哈</value><value>呵呵</value><value>嘿嘿</value></list></property><!-- ========================注入list======================== --><property name="list"><list><value>小雷</value><value>小风</value><value>小雨</value></list></property><!-- =======================注入set集合======================= --><property name="set"><set><value>set</value><value>集合</value></set></property><!-- =======================注入map集合======================= --><property name="map"><map><entry key="map01" value="1"></entry><entry key="map02" value="2"></entry><entry key="map03" value="3"></entry></map></property><!-- ==================注入properties属性文件================== --><property name="properties"><props><prop key="uname">root</prop><prop key="pass">123</prop></props></property></bean><!-- ===============依赖注入注入,引入其他的xml配置文件=============== --><!-- <import resource="character2.xml"/> --></beans>
测试类:
public class Test05 {@Testpublic void run(){ApplicationContext context = new ClassPathXmlApplicationContext("/character5.xml");CollectionBean bean = context.getBean("collectionBean",CollectionBean.class);System.out.println("复杂类型注入:" + bean);}
}
测试结果:
复杂类型注入:
CollectionBean [arrs=[哈哈, 呵呵, 嘿嘿],list=[小雷, 小风, 小雨],set=[set, 集合], map={map01=1, map02=2, map03=3}, properties={uname=root, pass=123}
]
5. 配置简写
让我们来总结一下依赖注入配置及简写形式,其实我们已经在以上部分穿插着进行简化配置了:
5.1 构造器注入
1)常量值
简写:<constructor-arg index="0" value="常量"/>
全写:<constructor-arg index="0"><value>常量</value></constructor-arg>
2)引用
简写:<constructor-arg index="0" ref="引用"/>
全写:<constructor-arg index="0"><ref bean="引用"/></constructor-arg>
5.2 setter注入
1)常量值
简写:<property name="message" value="常量"/>
全写:<property name="message"><value>常量</value></ property>
2)引用
简写:<property name="message" ref="引用"/>
全写:<property name="message"><ref bean="引用"/></ property>
3)数组:<array>没有简写形式
4)列表:<list>没有简写形式
5)集合:<set>没有简写形式
6)字典
简写:
<map>
<entry key="键常量" value="值常量"/>
<entry key-ref="键引用" value-ref="值引用"/>
</map>
全写:
<map>
<entry><key><value>键常量</value></key><value>值常量</value></entry>
<entry><key><ref bean="键引用"/></key><ref bean="值引用"/></entry>
</map>
7)Properties:没有简写形式
5.3 使用p命名空间简化setter注入
使用p命名空间来简化setter注入,具体使用如下:
<?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="bean1" class="java.lang.String"><constructor-arg index="0" value="test"/></bean>
<bean id="idrefBean1" class="cn.javass.spring.chapter3.bean.IdRefTestBean"
p:id="value"/>
<bean id="idrefBean2" class="cn.javass.spring.chapter3.bean.IdRefTestBean"
p:id-ref="bean1"/>
</beans>
- xmlns:p="http://www.springframework.org/schema/p" :首先指定p命名空间
- <bean id="……" class="……" p:id="value"/> :常量setter注入方式,其等价于<property name="id" value="value"/>
- <bean id="……" class="……" p:id-ref="bean1"/> :引用setter注入方式,其等价于<property name="id" ref="bean1"/>
(4)Spring框架----依赖注入(DI)相关推荐
- Spring框架—③依赖注入DI、Bean作用域及自动装配
依赖注入 DI,Dependency injection 依赖: 指bean对象的创建依赖于Spring容器 注入: 指Bean对象所依赖的资源,由容器来设置和装配 在beans.xml中配置 1.常 ...
- 框架学习 Spring之依赖注入DI
依赖注入的方式有四种: 1.Setter注入(属性注入) 2.构造器注入 3.P命名空间注入 4.集合类型值注入 1.Setter注入(属性注入) Employee 员工实体类 package com ...
- Spring字段依赖注入示例
学习如何编写Spring Field Injection示例 . 字段注入是Spring框架 依赖注入的一种 . 在本教程中,我们将编写几个类,并看一看现场注入工程. 有关Spring依赖注入的更多信 ...
- Spring的依赖注入(DI)和面向切面(AOP)代码解析说明
转载自: https://www.cnblogs.com/zmmi/p/7922186.html 1 依赖注入(DI) 大部分的Spring的新手(我)在学习之初对依赖注入这个词感到迷茫,事实上它并 ...
- java-12:spring MVC - 控制反转IOC,依赖注入DI
学习spring框架之前,先理解几个概念: 1.第一部分:依赖倒置原则 2.第二部分:控制反转,控制反转容器(实例) 3.第三部分:控制反转,控制反转容器(全面理解,面试题) 综合性理解:控制反转(I ...
- 框架源码系列九:依赖注入DI、三种Bean配置方式的注册和实例化过程
一.依赖注入DI 学习目标 1)搞清楚构造参数依赖注入的过程及类 2)搞清楚注解方式的属性依赖注入在哪里完成的. 学习思路 1)思考我们手写时是如何做的 2)读 spring 源码对比看它的实现 3) ...
- spring 04-Spring框架依赖注入基本使用
Spring的依赖注入形式实际上所有对象产生控制都要通过applicationContext.xml文件实现 依赖注入必须启动容器后才可以进行该配置文件的内部的加载操作 依赖注入之有参构造 定义一个D ...
- Spring框架----Spring的依赖注入
1.spring的依赖注入的概念 依赖注入:dependency Injection IOC的作用:降低程序之间的依赖关系,但不是消除. 依赖关系的管理:以后都交给了spring来维护 在当前类中需要 ...
- 框架依赖注入和普通依赖注入_依赖注入快速入门:它是什么,以及何时使用它...
框架依赖注入和普通依赖注入 by Bhavya Karia 通过Bhavya Karia 介绍 (Introduction) In software engineering, dependency i ...
- 控制反转IOC与依赖注入DI
为什么80%的码农都做不了架构师?>>> 1. IoC理论的背景 我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最 ...
最新文章
- python全栈开发中级班全程笔记(第二模块、第四章)(常用模块导入)
- UVa11137 Ingenuous Cubrency
- 记录执行hivesql时报org.apache.hadoop.hdfs.BlockMissingException:Could not obtain block错误
- HTML页面之间跳转与传值(JS代码)
- mysql查询时传入中文时的乱码问题
- Ubuntu技巧之xxx is not in the sudoers file解决方法
- oracle如何增加磁盘,牛刀小试Oracle之ORACLE 11GR2 RAC安装配置-asm磁盘组配置添加(四)...
- 图像去雾:基于暗通道的去雾算法 - 附代码
- web前端常用开发工具排行:8款html开发工具推荐下载
- 春节怎么抢红包,python一招告诉你再也不会错过微信红包
- 云计算与大数据作业 21大数据 刘佳琪
- Rhythmbox中文乱码解决
- 小米关机一直显示android,小米手机一直卡在fastboot怎么办
- 数据分析神器Alteryx
- 和平精英灵敏度分享码服务器没有响应,不求人灵敏度分享码 和平精英最新吃鸡灵敏度...
- CDR类CAD制作室内装修平面图
- 使用wcf编写坐标字符串生成shapefile文件,在iis发布供前端调用
- 找不到wpcap.dll解决方法
- cmd批量打开网页和关闭网页的批处理代码
- 系统管理员设置了系统策略,禁止进行此安装。