Di(Dependence Injection)依赖注入,在spring框架负责创建bean对象时,动态地将依赖对象注入到其它对象中
一、什么是依赖注入。
我们在下面构建spring的过程中体会依赖注入;
从上面的图中我们知道,在ssm框架中服务层(server)无法直接操作数据库,持久层(dao)是直接操作数据库进行数据处理的,但是我们如果在服务层有一个持久层的对象,然后我们在服务层通过对象去调用持久层的方法就可以操作数据库了。
package com.exam.dao;
public interface UserDao {
void hello();
}
package com.exam.dao.Impl;
import com.exam.dao.UserDao;
public class UserDaoImpl implements UserDao {
@Override
public void hello() {
System.out.println("持久层,你好");
}
}
UserServiceImpl类中的代码如下
package com.exam.service.impl;
import com.exam.dao.UserDao;
import com.exam.service.UserService;
public class UserServiceImpl implements UserService {
private UserDao userDao;
@Override
public void hello(){
userDao.hello();
}
}
这就是通过服务层去访问持久层的方法,我们在UserServiceImpl中定义了一个持久层(dao层)的对象UserDao,不过目前userDao对象还没有赋值,我们能想到的赋值方法应该只有使用new关键字。
private UserDao userDao = new UserDao()
而Di依赖注入就是使用Spring配置文件来完成赋值这一步(可以把依赖注入就理解为给属性赋值),这样代码维护起来会更加方便
二、依赖注入的方式
1.属性的set方法注入值的方式
我们需要在server层类中写一个set方法,如下
在UserServerImpl类中添加set方法
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
现在我们对xml文件进行配置
<bean id="us" class="com.exam.service.impl.UserServiceImpl">
<property name="userDao" value=""/>
</bean>
如果是要对某个类的对象进行管理使用的是<bean>,如果要对某个类中的对象进行管理,我们使用的就是<property>,这个过程就叫做依赖注入(Di),底层也是通过反射实现的
<property name="userDao" ref=""/>
<property name="age" value=""/>
在这个标签中,name的值代表了对象的属性名,ref和value都是给属性赋值,那么这两个的区别是什么呢?
ref和value的区别
如果是简单类型(基本类型+字符串)property标签使用value
如果是自定义引用类型, property标签使用ref
那么我们该怎么给ref和value赋值呢?
为了方便演示我们在UserServerImpl中添加了age属性和对应的set方法,下面是使用ref和value的应用情况。
<bean id="us" class="com.exam.service.impl.UserServiceImpl">
<property name="userDao" ref="ud"/>
<property name="age" value="18"/>
</bean>
<bean id="ud" class="com.exam.dao.Impl.UserDaoImpl"/>
我们分别在配置了依赖注入和未配置依赖注入的情况下执行test代码
@Test
public void run2(){
//创建spring ioc工厂,目的是加载spring配置文件
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//创建bean对象
UserService userService = (UserService) ac.getBean("us");
userService.hello();
}
没配置的情况
报错了显示空指针
配置了的情况
在依赖注入的情况下,我们想更改一个对象的值只需要更改配置文件就可以,不需要去找修改源代码,例如将年龄改成30,只需要更改,下面代码即可,维护起来更加方便。
<property name="age" value="18"/>
2.构造方法注入值的方法
首先在UserServerImpl中添加构造方法,记得还得写无参构造方法,不然IOC bean对象管理的时候会报错
public UserServiceImpl(UserDao userDao, int age) {
this.userDao = userDao;
this.age = age;
}
<bean id="us" class="com.exam.service.impl.UserServiceImpl">
<constructor-arg name="age" value="18"/>
<constructor-arg name="userDao" ref="ud"></constructor-arg>
</bean>
<bean id="ud" class="com.exam.dao.Impl.UserDaoImpl"/>
<constructor-arg>标签的name属性值,必须完全和构造方法中的形参对应,不能多不能少,比如构造方法中有name,那么<bean>标签中就不能只写
<constructor-arg name="userDao" ref="ud"></constructor-arg>
那么我们怎么通过依赖注入去给数组这种集合类的数据赋值呢?
1.不可变数组赋值
例如在CollectionNean类中
public class CollectionNean {
private String[] str;
public void setStr(String[] str) {
this.str = str;
}
}
我们的配置文件就应该这么写
<bean id="co" class="com.exam.service.impl.CollectionNean">
<property name="str">
<array>
<value>张三</value>
<value>小妹</value>
<value>小红</value>
</array>
</property>
</bean>
@Test
public void run2(){
//创建spring ioc工厂,目的是加载spring配置文件
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//创建bean对象
CollectionNean collectionNean = (CollectionNean) ac.getBean("co");
System.out.println(collectionNean.toString());
}
2.可变数组是怎么注入值的呢
这里指的是Java中的LIst<>类型
private List<String> list;
public void setList(List<String> list) {
this.list = list;
}
<property name="list">
<list>
<value>熊大</value>
<value>熊二</value>
</list>
</property>
3.给map类型注入值
private Map<String,String> map;
public void setMap(Map<String, String> map) {
this.map = map;
}
<property name="map">
<map>
<entry key="name" value="张三"></entry>
<entry key="age" value="31"></entry>
<entry key="sex" value="男"></entry>
</map>
</property>
4.给properties类型注入值
private Properties properties;
public void setProperties(Properties properties) {
this.properties = properties;
}
<property name="properties">
<props>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
三、多配置文件的加载方式:
1.在主配置文件中使用import
<import resource="applicationContext2.xml"/>
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
2.在创建工厂时直接加载多个配置文件
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml","applicationContext.xml2");