Bean的依赖注入分析
之前学的都是对Dao层的数据在Spring容器中的操作,然而在实际开发当中,除了Dao层,还有业务层和web层(就是controller层)也需要在Spring容器中操作。因为controller层中需要调用service层,而service层中又需要dao层数据。所以自然而然地,我们想到在Spring容器中写上两个bean,一个service层的bean,一个dao层的bean。
但是分析后可以知道,这样的做法其实是在容器外部获得UserService(即业务层)实例和UserDao实例(即Dao层)。
而我们的web层只需要调用service层就可以实现需要的操作,至于service层是如何调用dao层的,我们可以不用管理,这十分符合SpringIoc控制反转的理念,所以这里可以使用Spring依赖注入的方式,在Spring容器中将dao层实例注入service层中,而不用在程序中进行结合。
Bean的依赖注入概念
依赖注入(Dependency Injection):它是Spring框架核心IOC的具体实现。
在编写程序时,通过控制反转,把对象的创建交给了Spring,但是代码中不可能出现没有依赖的情况。IOC解耦只是降低他们的依赖关系,但不会消除。例如:业务层仍会调用持久层的方法。
那这种业务层和持久层的依赖关系,在使用Spring之后,就让Spring来维护了。
简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取。
Bean依赖注入的两种方式
1、set方法注入
2、构造器方式注入
Bean依赖注入之set方法注入
由上面的概述,我们现在来实操。
首先原来的UserServiceImpl类中因为需要调用dao层中UserDao的方法,所以原来是这么写的
package com.itheima.service.impl;
import com.itheima.dao.UserDao;
import com.itheima.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UserServiceImpl implements UserService {
public void save() {
//寻找Spring的配置文件
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
//id就是这里的Spring容器要创建的哪个bean对象的标识
UserDao userDao1 = (UserDao) app.getBean("userDao");
userDao1.save();
}
}
而现在因为Spring容器依赖注入了,那么上面save中的繁复操作就不再需要了。
变成这样:
package com.itheima.service.impl;
import com.itheima.dao.UserDao;
import com.itheima.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UserServiceImpl implements UserService {
/*设置一个UserDao类型的变量userDao,我们不需要赋给它值
因为在Spring内部中这个userDao(就是对应的id值)已经被Spring通过set方法
注入到了UserServiceImpl中,所以这个userDao是有值的
(之前想不明白的这里终于解决了(暴风哭泣))
*/
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void save() {
/*
因为Dao层的userDao已经由Spring容器帮忙创建注入service层了,
所以下面这一段userDao的创建就不再需要了
*/
// //寻找Spring的配置文件
// ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
// //id就是这里的Spring容器要创建的哪个bean对象的标识
// UserDao userDao = (UserDao) app.getBean("userDao");
userDao.save();
}
}
接下来要去配置文件中告诉Spring容器将dao实例依赖注入:
<?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">
<!--创建dao层的userDao实例-->
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"></bean>
<!--创建userService层的userService实例-->
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
<!--这个name要注意,它指的不是上面dao层的id值userDao
而是set方法名中除去set三个字母后后面剩下的字符串,且开头小写
(因为是set方法注入嘛)
如UserServiceImpl中的set方法为setUserDao,所以这里的name就是:userDao
-->
<!--对象的引用用ref
这里UserService对象通过id标识引用bean创建的dao对象,且因为dao对象中使用了set方法,而set方法中便设置了userDao的值,所以完成了依赖注入
总结起来就是,Java程序代码实现方式转换成了Spring容器中的代码实现方式而已
-->
<property name="userDao" ref="userDao"></property>
</bean>
</beans>
Bean依赖注入之构造器方法注入
大体流程和上面差不多
package com.itheima.service.impl;
import com.itheima.dao.UserDao;
import com.itheima.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UserServiceImpl implements UserService {
/*设置一个UserDao类型的变量userDao,我们不需要赋给它值
因为在Spring内部中这个userDao(就是对应的id值)已经被Spring通过有参构造方法
注入到了UserServiceImpl中,所以这个userDao是有值的
(之前想不明白的这里终于解决了(暴风哭泣))
*/
private UserDao userDao;
//设置有参构造器,将userDao注入UserServiceImpl中
public UserServiceImpl (UserDao userDao){
this.userDao = userDao;
}
//通常写了有参构造器也会将无参构造器写上,防止某些地方报错
public UserServiceImpl(){
}
public void save() {
/*
因为Dao层的userDao已经由Spring容器帮忙创建注入service层了,
所以下面这一段userDao的创建就不再需要了
*/
// //寻找Spring的配置文件
// ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
// //id就是这里的Spring容器要创建的哪个bean对象的标识
// UserDao userDao = (UserDao) app.getBean("userDao");
userDao.save();
}
}
然后在Spring配置文件中写上:
<?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">
<!--id叫什么名儿都行,然后后面的class跟上全类名-->
<!--创建dao层的userDao实例-->
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"></bean>
<!--创建userService层的userService实例-->
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
<!--这个name要注意,它指的不是上面dao层的id值userDao
而是有参构造器中传入的形参名
-->
<!--然后因为是有参构造器实现依赖注入,所以用constructor-arg标签注入
对象的引用用ref-->
<constructor-arg name="userDao" ref="userDao"></constructor-arg>
</bean>
</beans>
Bean的依赖注入的数据类型
上面的操作,都是注入的引用Bean,除了对象的引用可以注入外,普通数据类型,集合等都可以在容器中注入。
注入数据的三种类型:
1、普通数据类型
2、引用数据类型(就是上面的bean引入)
3、集合数据类型
普通数据类型引入代码演示
在UserDaoImpl中写上:
package com.itheima.dao.impl;
import com.itheima.dao.UserDao;
public class UserDaoImpl implements UserDao {
//为了演示普通数据类型引入
//声明两个普通数据
//这里就暂且使用set方法注入演示,而且一般是set方法注入
private String username;
private int age;
//我们在save方法中测试username和age是否有注入
public void save() {
System.out.println(username+"=="+age);
System.out.println("save running...");
}
}
然后在Spring配置文件中注入:
<?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">
<!--创建userDao实例-->
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
<!--给普通数据类型赋值用value,ref是给引用对象类型用的-->
<property name="username" value="zhangsan"></property>
<property name="age" value="22"></property>
</bean>
</beans>
集合数据类型引入代码演示
一样的,在UserDaoImpl中:
package com.itheima.dao.impl;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import java.util.List;
import java.util.Map;
import java.util.Properties;
public class UserDaoImpl implements UserDao {
//为了演示集合数据类型引入
//声明几个集合数据
private List<String> stringList;
private Map<String,User> userMap;
private Properties properties;
public void setStringList(List<String> stringList) {
this.stringList = stringList;
}
public void setUserMap(Map<String, User> userMap) {
this.userMap = userMap;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
//为了演示普通数据类型引入
//声明两个普通数据
//这里就暂且使用set方法注入演示,而且一般是set方法注入
private String username;
private int age;
public void setUsername(String username) {
this.username = username;
}
public void setAge(int age) {
this.age = age;
}
//我们在save方法中测试username和age还有集合数据是否有注入
public void save() {
// System.out.println(username+"=="+age);
System.out.println(stringList);
System.out.println(userMap);
System.out.println(properties);
System.out.println("save running...");
}
}
然后改配置文件
<?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">
<!--创建userDao实例-->
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
<!--这几个一般够用了,还有其他的其实都很类似,自己可以举一反三的-->
<!--注入List-->
<property name="stringList">
<list>
<value>aaa</value>
<value>bbb</value>
<value>ccc</value>
</list>
</property>
<!--注入Map-->
<property name="userMap">
<map>
<!--这里要使用引用类型User,所以要在Spring容器中
配置上User的bean实例
-->
<entry key="user1" value-ref="user1"></entry>
<entry key="user2" value-ref="user2"></entry>
</map>
</property>
<!--注入Properties-->
<property name="properties">
<props>
<!--这个稍微特殊点,记住格式就行了-->
<prop key="p1">ppp1</prop>
<prop key="p2">ppp2</prop>
<prop key="p3">ppp3</prop>
</props>
</property>
</bean>
<!--配置的User类型的实例-->
<bean id="user1" class="com.itheima.domain.User">
<property name="name" value="tom"></property>
<property name="addr" value="beijing"></property>
</bean>
<bean id="user2" class="com.itheima.domain.User">
<property name="name" value="lucy"></property>
<property name="addr" value="shanghai"></property>
</bean>
</beans>
Spring引入其他配置文件(分模块开发)
实际开发中,Spring的配置内容非常多,这就导致Spring配置很繁杂且体积很大,不易阅读也不易后期维护。所以,可以将部分配置拆解到其他配置文件中,而在Spring主配置文件中通过import标签进行加载。
<import>标签:导入其他的Spring的分文件。
<import resource=“applicationContext-xxx.xml”>