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对象
示例
1 2 3 4
| <bean id="userDao" class="cn.ywrby.dao.impl.UserDaoImpl" scope="singleton"></bean>
<bean id="userDao" class="cn.ywrby.dao.impl.UserDaoImpl" scope="prototype"></bean>
|
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
@Test public void userDaoTest(){ ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml"); 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:指定销毁方法,在对象被销毁时调用
1
| <bean id="userDao" class="cn.ywrby.dao.impl.UserDaoImpl" init-method="init" destroy-method="destroy"></bean>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 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的方法内进行修改,直接导致了代码耦合度变高
1 2 3 4 5 6 7 8 9 10 11
| public class UserServiceImpl implements UserService { @Override public void save() { 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的函数,直接利用成员变量进行操作即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class UserServiceImpl implements UserService { private UserDao dao;
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)
1 2 3 4
| <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>
|
测试用例:
1 2 3 4 5 6 7 8 9 10 11 12
|
@Test public void userServiceTest(){ ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml"); UserService service= (UserService) context.getBean("userService"); service.save(); }
|
P命名空间注入
这种注入方式本质还是set方法注入,只是通过利用P命名空间,简化了配置方法
在配置时首先需要定义P命名空间(第三行即定义P命名空间)
1 2 3 4
| <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命名空间的属性直接定义注入方法
1
| <bean id="userService" class="cn.ywrby.service.impl.UserServiceImpl" p:dao-ref="userDao"></bean>
|
构造函数注入
构造函数注入就是在创建对象A时调用对象A的有参构造函数,将指定的对象B作为参数注入对象A中
首先需要在被注入的对象中创建有参构造
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 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)
1 2 3 4
| <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中已经定义的引用数据类型,也有可能需要注入普通类型数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class UserDaoImpl implements UserDao {
private int num; private String name;
public void setNum(int num) { this.num = num; }
public void setName(String name) { this.name = name; }
public void save() { System.out.println(name+" : "+num); } }
|
修改配置文件
1 2 3 4
| <bean id="userDao" class="cn.ywrby.dao.impl.UserDaoImpl" > <property name="name" value="Leslie"/> <property name="num" value="18"/> </bean>
|
因为此时注入的是普通数据类型,所以不需要通过ref属性指定ID,此时直接通过value属性将要注入的值传入
集合数据类型的注入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class UserDaoImpl implements UserDao {
private List<String> nameList; private Map<String, User> userMap; private Properties properties;
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属性传入的,值是直接写在标签体中的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| <?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>
|
测试用例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Test public void userDaoTest3(){ ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml"); UserDao dao= (UserDao) context.getBean("userDao"); dao.save(); }
|
其他配置文件的引入
实际开发过程中我们所需要的配置文件可能是十分巨大的,内容十分杂乱,如果都定义在一个配置文件中,可读性和复写性都大打折扣
这种情况下我们可以将配置文件进行按模块拆分,或其他方式进行拆分,只需要最后在主配置文件中利用import标签进行引入即可
1 2 3
| <import resource="applicationContext-user.xml"/> <import resource="applicationContext-userDao.xml"/> <import resource="applicationContext-userService.xml"/>
|