我们先来思考
向一个类中传递数据的方式有几种?
依赖注入描述了在容器中建立 bean 与 bean 之间的依赖关系的过程,如果 bean 运行需要的是数字或字符串呢?
Spring 就是基于上面这些知识点,为我们提供了两种注入方式,分别是:
setter 注入
构造器注入
public class BookServiceImpl implements BookService { private BookDao bookDao; public void setBookDao(BookDao bookDao) { this.bookDao = bookDao; } }
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"> <property name="bookDao" ref="bookDao"/> </bean> <bean id="bookDao" class="com.itheima.dao.imipl.BookDaoImpl"/>
<?xml version="1.0" encoding="UTF-8"?> <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.xsd"> <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/> <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/> <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"> <property name="bookDao" ref="bookDao"/> <property name="userDao" ref="userDao"/> </bean> </beans>
思考:
引用类型使用的是<property name="" ref=""/>
,简单数据类型还是使用 ref 么?
ref 是指向 Spring 的 IOC 容器中的另一个 bean 对象的,对于简单数据类型,没有对应的 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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"> <property name="databaseName" value="mysql"/> <property name="connectionNum" value="10"/> </bean> <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/> <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"> <property name="bookDao" ref="bookDao"/> <property name="userDao" ref="userDao"/> </bean> </beans>
注意:两个 property 注入标签的顺序可以任意。
对于 setter 注入方式的基本使用就已经介绍完了,
<property name="" ref=""/>
<property name="" value=""/>
<?xml version="1.0" encoding="UTF-8"?> <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.xsd"> <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/> <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"> <constructor-arg name="bookDao" ref="bookDao"/> </bean> </beans>
说明:
标签
<?xml version="1.0" encoding="UTF-8"?> <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.xsd"> <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/> <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/> <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"> <constructor-arg name="bookDao" ref="bookDao"/> <constructor-arg name="userDao" ref="userDao"/> </bean> </beans>
说明:这两个<contructor-arg>
的配置顺序可以任意
<?xml version="1.0" encoding="UTF-8"?> <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.xsd"> <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"> <constructor-arg name="databaseName" value="mysql"/> <constructor-arg name="connectionNum" value="666"/> </bean> <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/> <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"> <constructor-arg name="bookDao" ref="bookDao"/> <constructor-arg name="userDao" ref="userDao"/> </bean> </beans>
说明:这两个<contructor-arg>
的配置顺序可以任意
上面已经完成了构造函数注入的基本使用,但是会存在一些问题:
在解决这个问题之前,需要提前说明的是,这个参数名发生变化的情况并不多,所以上面的还是比较主流的配置方式,下面介绍的,大家都以了解为主。
方式一:删除 name 属性,添加 type 属性,按照类型注入
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"> <constructor-arg type="int" value="10"/> <constructor-arg type="java.lang.String" value="mysql"/> </bean>
方式二:删除 type 属性,添加 index 属性,按照索引下标注入,下标从 0 开始
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"> <constructor-arg index="1" value="100"/> <constructor-arg index="0" value="mysql"/> </bean>
介绍完两种参数的注入方式,具体我们该如何选择呢?
强制依赖使用构造器进行,使用 setter 注入有概率不进行注入导致 null 对象出现
可选依赖使用 setter 注入进行,灵活性强
Spring 框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用 setter 注入完成可选依赖的注入
实际开发过程中还要根据实际情况分析,如果受控对象没有提供 setter 方法就必须使用构造器注入
自己开发的模块推荐使用 setter 注入
setter 注入
简单数据类型
<bean ...> <property name="" value=""/> </bean>
引用数据类型
<bean ...> <property name="" ref=""/> </bean>
构造器注入
简单数据类型
<bean ...> <constructor-arg name="" index="" type="" value=""/> </bean>
引用数据类型
<bean ...> <constructor-arg name="" index="" type="" ref=""/> </bean>
依赖注入的方式选择上
前面花了大量的时间把 Spring 的注入去学习了下,总结起来就一个字麻烦。
问:麻烦在哪?
答:配置文件的编写配置上。
问:有更简单方式么?
答:有,自动配置
IoC 容器根据 bean 所依赖的资源在容器中自动查找并注入到 bean 中的过程称为自动装配
自动装配只需要修改 applicationContext.xml 配置文件即可:
(1)将<property>
标签删除
(2)在<bean>
标签中添加 autowire 属性
首先来实现按照类型注入的配置
<?xml version="1.0" encoding="UTF-8"?> <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.xsd"> <bean class="com.itheima.dao.impl.BookDaoImpl"/> <!--autowire属性:开启自动装配,通常使用按类型装配--> <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byType"/> </beans>
注意事项:
NoUniqueBeanDefinitionException
一个类型在 IOC 中有多个对象,还想要注入成功,这个时候就需要按照名称注入,配置方式为:
<?xml version="1.0" encoding="UTF-8"?> <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.xsd"> <bean class="com.itheima.dao.impl.BookDaoImpl"/> <!--autowire属性:开启自动装配,通常使用按类型装配--> <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byName"/> </beans>
注意事项:
按照名称注入中的名称指的是什么?
bookDao 是 private 修饰的,外部类无法直接方法
外部类只能通过属性的 set 方法进行访问
对外部类来说,setBookDao 方法名,去掉 set 后首字母小写是其属性名
所以按照名称注入,其实是和对应的 set 方法有关,但是如果按照标准起名称,属性名和 set 对应的名是一致的
如果按照名称去找对应的 bean 对象,找不到则注入 Null
当某一个类型在 IOC 容器中有多个对象,按照名称注入只找其指定名称对应的 bean 对象,不会报错
两种方式介绍完后,以后用的更多的是按照类型注入。
最后对于依赖注入,需要注意一些其他的配置特征:
常见的集合类型
<property name="array"> <array> <value>100</value> <value>200</value> <value>300</value> </array> </property>
<property name="list"> <list> <value>itcast</value> <value>itheima</value> <value>boxuegu</value> <value>chuanzhihui</value> </list> </property>
<property name="set"> <set> <value>itcast</value> <value>itheima</value> <value>boxuegu</value> <value>boxuegu</value> </set> </property>
<property name="map"> <map> <entry key="country" value="china"/> <entry key="province" value="henan"/> <entry key="city" value="kaifeng"/> </map> </property>
<property name="properties"> <props> <prop key="country">china</prop> <prop key="province">henan</prop> <prop key="city">kaifeng</prop> </props> </property>
说明:
<array>
、<list>
、<set>
、<map>
、<props>
标签<list>
和<array>
标签是可以混用<value>
标签改成<ref>
标签,这种方式用的比较少