scope
spring中scope是一个非常关键的概念,简单说就是对象在spring容器(IOC容器)中的生命周期,也可以理解为对象在spring容器中的创建方式。
目前,scope的取值有5种取值:
在Spring 2.0之前,有singleton和prototype两种;
在Spring 2.0之后,为支持web应用的ApplicationContext,增强另外三种:request,session和global session类型,它们只实用于web程序,通常是和XmlWebApplicationContext共同使用
singleton
此取值时表明容器中创建时只存在一个实例,所有引用此bean都是单一实例。
也就是说创建对象是单例模式,并且如果不进行设置,默认就行单例
prototype
spring容器在进行输出prototype的bean对象 时,会每次都重新生成一个新的对象给请求方,虽然这种类型的对象的实例化以及属性设置等工作都是由容器负责的,但是只要准备完毕,并且对象实例返回给请求 方之后,容器就不在拥有当前对象的引用,请求方需要自己负责当前对象后继生命周期的管理工作,包括该对象的销毁。也就是说,容器每次返回请求方该对象的一 个新的实例之后,就由这个对象“自生自灭”,最典型的体现就是spring与struts2进行整合时,要把action的scope改为 prototype。
简单来说,就是每次获取都创建一个新对象,并且这个对象的生命周期不归Spring管理
session
Spring容器会为每个独立的session创建属于自己的全新的UserPreferences实例,比request scope的bean会存活更长的时间,其他的方面没区别,如同java web中session的生命周期。
配置scope方式
<bean name="userDao" class="com.tledu.zrz.dao.impl.UserDaoImpl"> <!-- 如果不是指向对象,直接用value设置值就行 --> <property name="daoId" value="82"></property> <property name="daoStatus" value="good"></property> </bean > <!-- scope singleton : 单例 只创建一个,默认就是 prototype : 每一次getBean 都会创建一个新的实例化对象 request,session : 需要特殊环境支持 --> <bean id="userService" class="com.tledu.zrz.service.UserService" scope="singleton"> <!-- 构造方法注入 --> <constructor-arg> <ref bean="userDao" /> </constructor-arg> </bean>
集合属性注入
相关类
UserDaoImpl中提供对应的变量
private List<String> lists; private Set<String> sets; private Map<String, String> maps; public List<String> getLists() { return lists; } public void setLists(List<String> lists) { this.lists = lists; } public Set<String> getSets() { return sets; } public void setSets(Set<String> sets) { this.sets = sets; } public Map<String, String> getMaps() { return maps; } public void setMaps(Map<String, String> maps) { this.maps = maps; }
配置文件
<bean name="userDao" class="com.tledu.zrz.dao.impl.UserDaoImpl"> <property name="lists" > <list> <value>1</value> <value>2</value> </list> </property> <property name="sets" > <!-- set不可重复,重复不添加,所以只有第一个三 --> <set> <value>3</value> <value>3</value> <value>5</value> <value>4</value> </set> </property> <property name="maps"> <!-- mapkey不可重复,重复key不添加,value覆盖 --> <map> <entry key="1" value="2"></entry> <entry key="1" value="3"></entry> <entry key="2" value="2"></entry> </map> </property> </bean> <bean id="userService" class="com.tledu.zrz.service.UserService" scope="singleton"> <!-- 构造方法注入 --> <constructor-arg> <ref bean="userDao" /> </constructor-arg> </bean>
自动装配有两种方式
1 set方法注入
<property name="userDao" ref="userDao" />
2 构造方法注入
<constructor-arg>
<ref bean="userDao"/>
</constructor-arg>
现在我们来学习自动注入,就是不需要指定以上两种方式
Autowire : 自动装配,两种取值
1 byName
2 byType
byName
byName是根据setter方法名字进行匹配,如果找不到,就不赋值
如 setUserDao 方法 就会找userDao,如果 bean的ID为 UserDao 也一样找不到,区分大小写
设置方式
<bean name="userDao" class="com.tledu.zrz.dao.impl.UserDaoImpl">
</bean>
<bean id="userService" class="com.tledu.zrz.service.UserService"
autowire="byName">
</bean>
byType
byType是根据setter方法的参数列表中的数据类型进行匹配,如果beans.xml中出现了多个相同类型的对象,就会报错
如 setUserDao(UserDao userDao) 方法 就会找UserDao,如果是接口,就找对应的实现类对象
设置方式
<bean name="userDao" class="com.tledu.zrz.dao.impl.UserDaoImpl">
</bean>
<bean id="userService" class="com.tledu.zrz.service.UserService"
autowire="byType">
</bean>
注意 : 使用自动装配,需要有公共的无参构造,虽然这里就算是私有化构造方法也依然可以创建对象,但是还是提供一个公共的比较好,万一别的框架需要呢
constructor
可以根据构造函数进行依赖的注入。
生命周期和迟加载
构造方法 -- init -- service -- destroy
Spring中是没有init、service和destroy的,但是我们可以指定某个方法在创建完对象之后执行,某个方法在最后销毁的时候执行.
生命周期
相关类
UserService中提供对应的方法
public void init(){ System.out.println("init--------"); } public void destroy(){ System.out.println("destroy----------"); } public UserService() { System.out.println("service构造方法"); }
配置文件
<bean name="userDao" class="com.tledu.zrz.dao.impl.UserDaoImpl" > </bean> <!-- init-method : 用于设置初始化的方法 destory-method : 用于设置销毁资源的方法 --> <bean id="userService" class="com.tledu.zrz.service.UserService" autowire="byName" init-method="init" destroy-method="destroy" > </bean>
Destroy之所以会执行,是因为我们默认创建对象的时候是单例模式
这个时候对象的生命周期会和Spring容器的生命周期绑定到一起,所以当我们销毁Spring容器的时候,会把所有的对象销毁,并自动调用destroy方法
但是如果我们把scope设置为prototype的时候,对象的生命周期就不会再和Spring容器绑定,销毁Spring容器的时候也就不会再执行该对象的destroy方法
注意:scope为prototype类型时,我们容器只负责实例的创建,创建之后的生命周期由调用者负责。
迟加载
Spring容器默认是在执行
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
进行解析的时候创建对象并调用init,
如果我们不想让某个类在解析的时候就创建对象,而是用到的时候在创建对象的话,就需要设置迟加载
比如想要对userService迟加载可以这样设置
相关类
在UserDaoImpl和UserService中的构造方法添加输出语句进行测试
public UserDaoImpl(){ System.out.println("Dao构造方法"); } public UserService() { System.out.println("service构造方法"); }
配置文件
<bean name="userDao" class="com.tledu.zrz.dao.impl.UserDaoImpl" > <bean id="userService" class="com.tledu.zrz.service.UserService" scope="prototype" autowire="byName" init-method="init" destroy-method="destroy" lazy-init="true" > </bean>
2.1.2.3 测试
@Test public void testAdd() { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext( "beans.xml"); }
为了使用方便,Spring还提出了default-lazy-init="true"
比如我们通过xml创建了10个对象,这10个对象都需要迟加载,那么每个bean标签中都设置lazr-init是比较麻烦的
于是我们可以在beans标签中添加default-lazy-init="true" 对所有的bean进行迟加载
default-lazy-init 和 lazy-init 可以同时存在,比如 10个对象中 只有一个不需要迟加载,那么可以使用 default-lazy-init = true 全部设置迟加载,然后再去指定的bean中添加 lazy-init=false 就可以