关于Spring中Bean对象的单例和多例
在Spring容器中管理的Bean对象的作用域,可以通过scope属性或者用相关的注解方式指定该Bean对象的作用域。最常用的是两种,一种是单例(Singleton)另一种是多例(prototype)。
1、Singleton:单实例,此为Spring中的bean的默认设置值,该作用域标识的对象具有全局唯一特性。
当一个bean的scope为singleton作用域的时候,那么SpringIOC容器只会为该bean创建定义唯一的实例,也就是说整个SpringIOC容器指挥创建当前类的唯一一个对象。且这个单一实例会存储到单例缓存中,所有针对于该bean的后续请求和引用都会返回该bean被缓存存储的、唯一的该对象的实例。
Singleton单实例会负责对象的创建、初始化、销毁。
2、prototype:多实例。这个作用域标识的对象每次获取都会创建新的对象。
当一个bean的scope设置为prototype作用域的时候,SpringIOC容器在每一次获取当前bean的时候,都会创建一个新的Bean实例(可以理解为每次都会new的操作但本质上不是传统的new对象因为ioc)
prototype多实例只负责对象的创建、初始化,不负责销毁。
单实例和多实例的使用
为什么使用单实例?
在没有线程安全问题的前提下,没有必要为每一次的请求都创建一个对象,浪费内存空间浪费CPU,不划算不合适。
为什么使用多实例?
使用多实例是为了防止并发问题,即假如一个请求改变了对象的状态(例如,可改变的成员变量),此时对象又处理另一个请求的时候,此前请对该对象状态的改变导致了对象对另一个请求做出了错误的处理这种情况。
在Spring中配置Bean
单例:
<bean id=“user” scope=“singleton” class=“包名.user”></bean>
多例:
<bean id=''user'' scope=''prototype'' class=''包名.user’‘></bean>
测试Spring的单实例和多实例
1、创建Test测试类
package com.spring;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
/* 通过spring容器创建创建User对象,
* 并调用User中的sayHi方法 */
//1.加载spring的核心配置文件
ClassPathXmlApplicationContext ac =
new ClassPathXmlApplicationContext(
"applicationContext.xml"
);
//2.从spring容器中获取bean对象(而不是自己new)
User user1 = (User) ac.getBean("user");
User user2 = (User) ac.getBean("user");
//3.测试
if(user1 == user2){
System.out.println("当前实例为单实例...");
}else{
System.out.println("当前实例为多实例...");
}
}
}
2、将applicationContext.xml中,User类bean标签的scope值设置为singleton:
<bean id=’‘user’‘ scope=’‘singleton’‘ class=’‘package com.spring’‘></bean>
运行test测试类输出:当前实例为单实例…
3、将applicationContext.xml中,User类bean标签的scope值修改为prototype
<bean id="user" scope="prototype" class="com.spring.User"></bean>
运行test测试类输出:当前实例为多实例…
Spring DI依赖注入
主要介绍两种依赖注入方式
( 1 )Set方式注入
( 2 )构造方法注入
依赖注入:即组件之间的依赖关系由容器在应用系统运行期间所决定的,额就是说由容器动态的将某种依赖关系的目标对象实例注入到应用系统中的各个关联的组件之中。
换句话简单的说,依赖注入即为在创建对象的同时或者创建对象之后如何给对象的属性赋值。
自己创建的对象依赖注入:
User user = new User();
user.setNane(''六六六'');
user.setAge(18);
或者
User user = new User(’‘六六六’‘,18);
( 1 )Set方式注入-----普通属性注入
要求:通过Spring创建User实例,并且为User实例的name和age属性赋值
1、创建一个User类,生命name和age属性,并添加相应的setter和getter方法以及toString方法
package.com.spring
public class User{
private Sring name;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString(){
return "User [name=" + name + ", age=" + age + "]";
}
}
2、在applicationContext.xml中声明User类的bean实例
<!-- 声明User类的bean实例 -->
<bean id="user" class="com.spring.User"></bean>
3、创建测试类—TestDI
package com.spring;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestDI {
public static void main(String[] args) {
//1.加载applicationContext.xml核心配置文件
ClassPathXmlApplicationContext ac =
new ClassPathXmlApplicationContext(
"applicationContext.xml"
);
//2.获取User类的实例
User user = (User) ac.getBean("user");
//3.输出User实例
System.out.println( user );
}
}
此时,并没有给User对象的name和age属性赋值,所以如果运行TestDI测试类,得到的打印结果为User[name=null,age=null]
4、修改applicationContext.xml中的User实例的声明,为User实例注入属性
<!-- 声明User类的bean实例 -->
<bean id="user" class="com.spring.User">
<!-- 通过set方式为普通属性赋值 -->
<property name="name" value="六六六"></property>
<property name="age" value="20"></property>
</bean>
注意:prototype标签中的nama属性的值,必须和User类中所注入的属性的对应的方法名字去掉get后的首字母变为小写后的名字相同,普通的属性直接通过value方式注入即可。
5、运行测试类testDI
上面通过spring提供的set方法对User对象的属性进行了赋值操作,再运行测试类testDI
User [name=六六六,age=20]
-----对象属性注入
要求:通过Spring创建User实例并且为User对象的userInfo属性(对象属性)赋值
1、创建UserInfo类
package com.spring
public class UserInfo{
}
2、在qpplicationContext.xml中声明UserInfo类的bean实例
<!-- 声明UserInfo类的bean实例 -->
<bean id="userInfo" class="com.spring.UserInfo"></bean>
3、修改User类,声明userInfo属性,添加对应的setter和getter方法,并重新生成toString方法
public class User{
...
private UserInfo userInfo;
public UserInfo getUserInfo() {
return userInfo;
}
public void setUserInfo(UserInfo userInfo) {
this.userInfo = userInfo;
}
...
public String toString() {
return "User [name=" + name + ", age=" + age + ", userInfo=" + userInfo + "]";
}
}
4、在applicationContext.xml中,将UserInfo对象作为值,赋值给User对象的userInfo属性
<!-- 声明User类的bean实例 -->
<bean id="user" class="com.spring.User">
<!-- 通过set方式为普通属性赋值 -->
<property name="name" value="韩少云"></property>
<property name="age" value="20"></property>
<!-- 通过set方式为对象属性赋值 -->
<property name="userInfo" ref="userInfo"></property>
</bean>
property标签中的ref属性:查找当前配置文件里的bean,对象属性通过property标签中的ref属性注入。
5、运行测试类TestDI
User [name=’‘六六六’’,age=20,userInfo=com.spring.UserInfo@59494225]
构造方法注入
要求:通过Spring创建User对象,并且为User对象的属性(name\age\UserInfo属性)赋值
1、为User类声明构造造数
//声明无参构造函数
public User() {
}
//声明有参构造函数
public User(String name, Integer age, UserInfo userInfo) {
super();
this.name = name;
this.age = age;
this.userInfo = userInfo;
}
2、修改applicationContext.xml文件,将set方式修改为构造方法注入
<bean id="user" class="com.tedu.spring.User">
<!-- 通过set方式为普通属性赋值
<property name="name" value="韩少云"></property>
<property name="age" value="20"></property>
<property name="userInfo" ref="userInfo"></property>
-->
<!-- 通过构造器中参数为属性赋值 -->
<constructor-arg name="name" value="马云"></constructor-arg>
<constructor-arg name="age" value="35"></constructor-arg>
<constructor-arg name="userInfo" ref="userInfo"></constructor-arg>
</bean>
<!-- 声明UserInfo类的bean实例 -->
<bean id="userInfo" class="com.tedu.spring.UserInfo"></bean>
注意:constrctor-arg标签name属性的值必须和构造函数中参数的名字相同:
同样的,普通属性直接通过value注入即可;
对象属性通过ref属性注入。
3、运行测试类TestDI
User [name=’‘七七七’’,age=30,userInfo=com.spring.UserInfo@ff5b51f]
PS:
关于applicationContext.xml没有提示的解决办法
1、配置spring-beans-4.1.xsd文件
(1)找到spring-beans-4.1.xsd
(2)复制下面的url地址打开
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
(3)在eclipse菜单栏中:window–>Preferences–>搜索xml catelog–>User Specified Entries–>Add
(4)在弹出的窗口中:
在Location栏中填写spring-context-4.1.xsd文件的路径
在key type栏中选择Schema location
Key栏中填写http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
点击OK即可
------有待补充