目录
一:Bean的作用域
1. singleton(单例)
2. prototype(多例)
3. 其它scope
4. 自定义scop(了解)
(1)默认情况下,Spring的IoC容器创建的Bean对象是单例的(singleton)!
在Spring上下文对象初始化的时候实例化!
SpringBean类
package com.bjpowernode.spring6.bean;
public class SpringBean {
}
spring-scop.xml配置
测试程序
package com.bjpowernode.spring6.test;
import com.bjpowernode.spring6.bean.SpringBean;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringScopTest {
@Test
public void testScop(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-scop.xml");
SpringBean sb1 = applicationContext.getBean("springBean", SpringBean.class);
System.out.println(sb1);
// 访问同一个对象
SpringBean sb2 = applicationContext.getBean("springBean", SpringBean.class);
System.out.println(sb2);
}
}
执行结果:
通过测试验证:Spring的IoC容器中,默认情况下,Bean对象是单例的!
(2)这个对象在什么时候创建的呢?
可以为SpringBean提供一个无参数构造方法,进行测试:
SpringBean类
package com.bjpowernode.spring6.bean;
public class SpringBean {
public SpringBean() {
System.out.println("SpringBean的无参数构造方法执行了!");
}
}
将测试程序中getBean()所在行代码注释掉
package com.bjpowernode.spring6.test;
import com.bjpowernode.spring6.bean.SpringBean;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringScopTest {
@Test
public void testScop(){
new ClassPathXmlApplicationContext("spring-scop.xml");
}
}
执行结果:
通过测试得知,默认情况下,Bean对象的创建是在初始化Spring上下文的时候就完成的!
调用getBean方法只是从Map集合当中取出数据!
(1)那么就要创建多例的怎么办呢?
如果想让Spring的Bean对象以多例的形式存在,可以在bean标签中指定scope属性的值为:prototype(原型、多例)!
spring-scop.xml配置
增加了scope属性,目前来说scope属性有两个值:
第一个值:singleton 单例(默认情况下不设置就是单例的)
第二个值:prototype 原型/多例
执行结果:
得到两次创建的内存地址就不一样了,多例!
(2)此时是什么时候创建对象呢?
在初始化上下文对象时不会创建对象,每一次执行getBean()方法的时候创建Bean对象,调用几次则创建几次!
SpringBean类
package com.bjpowernode.spring6.bean;
public class SpringBean {
public SpringBean() {
System.out.println("SpringBean的无参数构造方法执行了!");
}
}
将测试程序中getBean()所在行代码注释掉
package com.bjpowernode.spring6.test;
import com.bjpowernode.spring6.bean.SpringBean;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringScopTest {
@Test
public void testScop(){
new ClassPathXmlApplicationContext("spring-scop.xml");
}
}
执行结果:
此时并没有执行构造方法,通过测试验证确实是调用getBean方法的时候创建对象!
scope属性的值不止两个,它一共包括8个选项:
①singleton:默认的,单例。
②prototype:原型。每调用一次getBean()方法则获取一个新的Bean对象,或每次注入的时候都是新对象。
③request:一个请求对应一个Bean。仅限于在WEB应用中使用。
④session:一个会话对应一个Bean。仅限于在WEB应用中使用。
⑤global session:portlet应用中专用的。如果在Servlet的WEB应用中使用global session的话,和session一个效果。(portlet和servlet都是规范。servlet运行在servlet容器中,例如Tomcat。portlet运行在portlet容器中。)
⑥application:一个应用对应一个Bean。仅限于在WEB应用中使用。
⑦websocket:一个websocket生命周期对应一个Bean。仅限于在WEB应用中使用。
⑧自定义scope:很少使用。
例如:在pom.xml文件当中引入web的框架springmvc
org.springframework
spring-webmvc
6.0.0-M2
此时的scop值就可以使用request和session的值
接下来自定义一个Scope,线程级别的Scope!
在同一个线程中,获取的Bean都是同一个;如果是跨线程则是不同的对象!
(1)先测试单例模式下开启多线程创建的是几个Bean对象
package com.bjpowernode.spring6.test;
import com.bjpowernode.spring6.bean.SpringBean;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringScopTest {
@Test
public void testThradScop(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-scop.xml");
// 主线程
SpringBean sb1 = applicationContext.getBean("springBean", SpringBean.class);
System.out.println(sb1);
SpringBean sb2 = applicationContext.getBean("springBean", SpringBean.class);
System.out.println(sb2);
// 启动一个新的线程
new Thread(new Runnable() {
@Override
public void run() {
SpringBean sb3 = applicationContext.getBean("springBean", SpringBean.class);
System.out.println(sb3);
SpringBean sb4 = applicationContext.getBean("springBean", SpringBean.class);
System.out.println(sb4);
}
}).start();
}
}
测试结果:单例模式,拿到的都是同一个Bean对象
(2)测试自定义scop
第一步:自定义Scope(实现Scope接口)
实际上spring内置了线程范围的类:org.springframework.context.support.SimpleThreadScope,可以直接用!
第二步:将自定义的Scope注册到Spring容器中
注册的时候需要用到自定义范围配置器CustomScopeConfigurer(自定义范围配置器)
第三步:使用Scope
完整的spring-cope.xml配置如下:
第四步:执行结果
还是同样的测试代码,可以看出:
对于同一个线程访问的是同一个Bean对象;对于不同的线程访问的是不同的对象!