Spring配置文件
Bean标签基本配置
用于配置对象交由Spring来创建,默认情况下调用的是类中的无参构造函数,没有无参构造的情况下不能创建成功
基本属性
- id:Bean实例在Spring中的唯一标识
- class:Bean的全限定名称
Bean标签范围配置
scope属性
取值范围 | 说明 |
---|---|
singleton | 默认值,单例的 |
prototype | 多例的 |
request | web项目中,Spring创建一个对象并将对象存入request域内 |
session | web项目中,Spring创建一个对象并将对象存入session域内 |
global session | web项目中,应用在Portlet环境,如果没有Portlet环境,global session相当于session |
这里单例是指每次创建出的Bean对象都是同一个对象,而多例则表示每次创建的都是全新的不同的Bean对象
示例
代码语言:javascript复制<!--单例的-->
<bean id="userDao" class="cn.ywrby.dao.impl.UserDaoImpl" scope="singleton"></bean>
<!--多例的-->
<bean id="userDao" class="cn.ywrby.dao.impl.UserDaoImpl" scope="prototype"></bean>
测试
代码语言:javascript复制/**
* 测试scope属性
*/
@Test
public void userDaoTest(){
//指定配置文件
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
//通关配置文件与ID获取实例
UserDao dao1= (UserDao) context.getBean("userDao");
UserDao dao2= (UserDao) context.getBean("userDao");
//输出两个对象的地址即可判断是否两次创建为同一对象
System.out.println(dao1);
System.out.println(dao2);
}
singleton与prototype的区别
当scope取值为singleton时,Bean实例化的个数始终是一个,并且实例化的时机是在Spring核心文件(配置文件)被加载时
当scope取值为prototype时,Bean实例化的个数是多个,此时实例化的时机不是核心文件加载,而是在每次调用getBean方法时创建
Bean声明周期的配置
- init-method:指定初始化方法,在对象创建时被调用
- destroy-method:指定销毁方法,在对象被销毁时调用
<bean id="userDao" class="cn.ywrby.dao.impl.UserDaoImpl" init-method="init" destroy-method="destroy"></bean>
代码语言:javascript复制public class UserDaoImpl implements UserDao {
public void init(){
System.out.println("执行初始化...");
}
public void destroy(){
System.out.println("执行销毁...");
}
public void save() {
System.out.println("Save Running...");
}
}
Spring依赖注入
概念
依赖注入(Dependency Injection)是Spring框架核心IOC的具体实现
Bean对象的注入(引用数据类型的注入)
依赖注入的主要目的还是解耦,主要利用的原理就是控制反转,即将构造对象这个【控制】交给了第三方Spring来进行操作
我们在实际的项目开发中,必然涉及到对多个对象的构造与控制,而我们许多的对象已经预定义在Spring容器中(那些已经在配置文件中定义的对象)。
此时假如我们需要在某个Spring容器中已有的对象A内调用另一个同样已经在Spring容器中定义的对象B,一般情况我们会直接在对象A中加载配置文件,利用Spring获取对象B,然后再操作获取到的对象
这种情况下假如我们需要修改代码,就需要到所有操作配置文件获取对象B的方法内进行修改,直接导致了代码耦合度变高
代码语言:javascript复制public class UserServiceImpl implements UserService {
@Override
public void save() {
//UserService与UserDao都是定义在Spring容器中的对象
//这里在UserService的save方法中利用配置文件获取了UserDao对象
//这也就导致了代码耦合度很高,不便于复用和修改
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao dao= (UserDao) context.getBean("userDao");
dao.save();
}
}
要解决这种问题就可以利用依赖注入,第一种方式是set方法注入,第二种是构造函数注入
set方法注入
即通过在配置文件中提前配置,使得在创建对象A时调用指定的set方法将对象B直接传入对象A内部,这样的注入方式保证了对象B没有在对象A的方法中进行实例化,而是作为参数直接传入A内部,需要使用对象B时直接使用传入的对象即可。需要修改代码时只需要对配置文件进行修改即可
首先在被传入的Bean中定义传入参数的set方法,并且定义成员变量用于接收传入的参数,修改调用对象B的函数,直接利用成员变量进行操作即可
代码语言:javascript复制public class UserServiceImpl implements UserService {
private UserDao dao; //定义成员变量
//定义set方法,用于其他对象的传入
public void setDao(UserDao dao) {
this.dao = dao;
}
@Override
public void save() {
//修改成员方法,可以直接利用成员变量进行操作
//省去了对配置文件的使用,降低了代码耦合度
dao.save();
}
}
然后修改配置文件,指定在创建UserService时调用指定的set方法注入相关参数(利用property标签进行指定 其中name是set方法后面的后缀并首字母小写,例如setDao方法,这里就传入dao,setUserService方法就传入userService ,ref是要传入的Spring容器中对象的ID)
代码语言:javascript复制<bean id="userDao" class="cn.ywrby.dao.impl.UserDaoImpl" ></bean>
<bean id="userService" class="cn.ywrby.service.impl.UserServiceImpl" >
<property name="dao" ref="userDao"></property>
</bean>
测试用例:
代码语言:javascript复制/**
* 测试依赖注入
*/
@Test
public void userServiceTest(){
//指定配置文件
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
//通关配置文件与ID获取实例
UserService service= (UserService) context.getBean("userService");
//执行方法
service.save();
}
P命名空间注入
这种注入方式本质还是set方法注入,只是通过利用P命名空间,简化了配置方法
在配置时首先需要定义P命名空间(第三行即定义P命名空间)
代码语言:javascript复制<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/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
利用P命名空间的属性直接定义注入方法
代码语言:javascript复制<bean id="userService" class="cn.ywrby.service.impl.UserServiceImpl" p:dao-ref="userDao"></bean>
构造函数注入
构造函数注入就是在创建对象A时调用对象A的有参构造函数,将指定的对象B作为参数注入对象A中
首先需要在被注入的对象中创建有参构造
代码语言:javascript复制public class UserServiceImpl implements UserService {
private UserDao dao; //定义成员变量
//定义有参构造
public UserServiceImpl(UserDao dao) {
this.dao = dao;
}
public UserServiceImpl(){}
@Override
public void save() {
//修改成员方法,可以直接利用成员变量进行操作
//省去了对配置文件的使用,降低了代码耦合度
dao.save();
}
}
然后在配置文件中声明要调用有参构造,并指定传入的对象在Spring容器中的ID(利用constructor-arg标签指定要传入的参数,name属性表示的是传入的对象命名,ref属性是传入参数在Spring容器中的ID)
代码语言:javascript复制<bean id="userDao" class="cn.ywrby.dao.impl.UserDaoImpl" ></bean>
<bean id="userService" class="cn.ywrby.service.impl.UserServiceImpl" >
<constructor-arg name="dao" ref="userDao"></constructor-arg>
</bean>
普通数据类型的注入
在使用中,我们除了可能注入Spring中已经定义的引用数据类型,也有可能需要注入普通类型数据
代码语言:javascript复制public class UserDaoImpl implements UserDao {
//定义普通数据类型的成员变量
private int num;
private String name;
//定义set方法
public void setNum(int num) {
this.num = num;
}
public void setName(String name) {
this.name = name;
}
public void save() {
System.out.println(name " : " num);
}
}
修改配置文件
代码语言:javascript复制<bean id="userDao" class="cn.ywrby.dao.impl.UserDaoImpl" >
<property name="name" value="Leslie"/>
<property name="num" value="18"/>
</bean>
因为此时注入的是普通数据类型,所以不需要通过ref属性指定ID,此时直接通过value属性将要注入的值传入
集合数据类型的注入
代码语言:javascript复制public class UserDaoImpl implements UserDao {
//定义集合数据类型
private List<String> nameList;
private Map<String, User> userMap;
private Properties properties;
//定义set方法
public void setNameList(List<String> nameList) {
this.nameList = nameList;
}
public void setUserMap(Map<String, User> userMap) {
this.userMap = userMap;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
public void save() {
System.out.println(nameList);
System.out.println(userMap);
System.out.println(properties);
}
}
以下是集合数据类型注入时配置文件的配置方式
可以看到List类型注入时只需要定义value标签即可,标签体内传注入的值
Map类型在注入时需要利用entry标签传入键和值,键和值都可以使用引用类型或普通类型,引用类型只需要在后面加“-ref”即可
properties类型注入时和Map类似,也需要传入键和值,但是键是通过key属性传入的,值是直接写在标签体中的
代码语言:javascript复制<?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="userDao" class="cn.ywrby.dao.impl.UserDaoImpl" >
<property name="nameList">
<list>
<value>Leslie</value>
<value>Ywrby</value>
</list>
</property>
<property name="userMap">
<map>
<entry key="1" value-ref="user1"></entry>
<entry key="2" value-ref="user2"></entry>
</map>
</property>
<property name="properties">
<props>
<prop key="p1">value1</prop>
<prop key="p2">value2</prop>
</props>
</property>
</bean>
<bean id="user1" class="cn.ywrby.domain.User">
<property name="name" value="Jessica"></property>
<property name="addr" value="Peking"></property>
</bean>
<bean id="user2" class="cn.ywrby.domain.User">
<property name="name" value="Lere"></property>
<property name="addr" value="SJZ"></property>
</bean>
<bean id="userService" class="cn.ywrby.service.impl.UserServiceImpl" >
<constructor-arg name="dao" ref="userDao"></constructor-arg>
</bean>
</beans>
测试用例:
代码语言:javascript复制@Test
public void userDaoTest3(){
//指定配置文件
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
//通关配置文件与ID获取实例
UserDao dao= (UserDao) context.getBean("userDao");
//执行方法
dao.save();
}
/*
运行结果:
[Leslie, Ywrby]
{1=User{name='Jessica', addr='Peking'}, 2=User{name='Lere', addr='SJZ'}}
{p1=value1, p2=value2}
*/
其他配置文件的引入
实际开发过程中我们所需要的配置文件可能是十分巨大的,内容十分杂乱,如果都定义在一个配置文件中,可读性和复写性都大打折扣
这种情况下我们可以将配置文件进行按模块拆分,或其他方式进行拆分,只需要最后在主配置文件中利用import标签进行引入即可
代码语言:javascript复制<import resource="applicationContext-user.xml"/>
<import resource="applicationContext-userDao.xml"/>
<import resource="applicationContext-userService.xml"/>