本章补充bean的作用域和自动装配
bean作用域
之前提到可以用scope来设置单例模式
<bean id="type" class="cn.dota2.tpye.Type" scope="singleton"></bean>
除此之外还有几种用法
singleton:单例模式,Spring默认使用单例模式,也是开发中最常用的类型。即:加载bean配置文件只能生成类的一个实例,只会new一次。
prototype:多例模式,用到一次就会new一次。因为对象多,所以不会销毁。
request:应用在web项目中,Spring创建这个类之后,将这个类存到request范围内。
session:应用在web项目中,Spring创建这个类之后,将这个类存到session范围内。
globalsession:应用在web项目中,必须在portlet环境下才能使用。即在系统下存入数据后,在其子系统下就不需要重新登录。
注意默认情况下bean的作用域是单例。之前我有个疑问,既然是单列,为什么可以在java代码中创建两个实例对象?如下图
ApplicationContext ac=new ClassPathXmlApplicationContext("beans.xml");
Student student=(Student)ac.getBean("student");
Student student1=(Student)ac.getBean("student");
其实这里的getBean获取的bean都是一个bean。我们改student的名字,student1的名字也会改变。因为student在容器里只有一个。
ApplicationContext ac=new ClassPathXmlApplicationContext("beans.xml");
Student student=(Student)ac.getBean("student");
Student student1=(Student)ac.getBean("student");
student.show();
student.setName("王五");
student1.show();
改成prototype
<bean id="student" class="cn.dota2.hero.Student" scope="prototype">
<property name="name" value="张三"/>
</bean
ApplicationContext ac=new ClassPathXmlApplicationContext("beans.xml");
Student student=(Student)ac.getBean("student");
Student student1=(Student)ac.getBean("student");
student.show();
student.setName("王五");
student.show();
student1.show();
bean自动装配
一个bean文件可能需要引用其他很多bean,这样配置文件可能会很复杂,所有有了自动装配来简化spring。
常规引用
package cq.school.student;
import cq.school.School;
public class Student {
School school=null;
public School getSchool() {
return school;
}
public void setSchool(School school) {
this.school = school;
}
public void show(){
school.getSchool();
}
}
bean配置
<bean id="frist" class="cq.school.FristSchool"/>
<bean id="second" class="cq.school.SecondSchool"/>
<bean id="student" class="cq.school.student.Student">
<property name="school" ref="frist"/>
自动装配有几种种
通过byname自动装配。
<bean id="student" class="cq.school.student.Student" autowire="byName">
这里的name是Student中的setSchoole中的school。它会在bean容器中寻找name相符合的自动装配。所以需要更改frist或者second的id或者name。代码如下
<bean id="school" class="cq.school.SecondSchool"/>
<bean id="student" class="cq.school.student.Student" autowire="byName">
java代码中给school赋值的方法时setSchool,所以会把id为school传给student。
通过byType装配。
<bean class="cq.school.FristSchool"/>
<bean class="cq.school.SecondSchool"/>
<bean id="student" class="cq.school.student.Student" autowire="byType"/>
和byname相似,会自动寻找类型相符合的装配,测试一下
报错原因是因为一中和二中都是符合类型的,要删除一个才行,用bytpye装配需要整个容器只有一个相符合的类型。删除一个后
<bean class="cq.school.SecondSchool"/>
<bean id="student" class="cq.school.student.Student" autowire="byType"/>
如果所有配置都需要用到一种配置方式,可以在头文件中加入default-autowire="byName"。或者换成其他配置方法
<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-2.5.xsd" default-autowire="byName">
consrtuctor注入。
通过构造器注入。适用于bytype得而方式装配构造器,修改一下student的代码,去掉set方法,让它在构造方法里面设置school。
package cq.school.student;
import cq.school.School;
public class Student {
School school=null;
public Student(School school){//修改处
this.school=school;
}
public School getSchool() {
return school;
}
public void show(){
school.getSchool();
}
}
自动装配改成改成constructor注入
<?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-2.5.xsd" default-autowire="byName">
<bean class="cq.school.SecondSchool"/>
<bean id="student" class="cq.school.student.Student" autowire="constructor"/>
</beans>
结果一样。
总结
在配置bean时,有 scope属性,可以配置bean作用域,在整合struts2和spring时,需要将action设为scope=“prototype”;(目前不知道为啥,反正记住),关于自动装配,用于减少配置文件。我自己感觉自动装配虽然简洁了代码,但是太过简洁反而不利于阅读,特别是bytype装配,bean一旦太多,就容易出bug,而且不好排查。建议少用。