Bean的作用域
Bean的作用域有很多种,在Spring Framework中支持6种(其中有四种只有在web环境中才能生效),同时Spring还支持自定义Bean的范围。
Spring Framework中支持的6种范围:
作用域 | 解释 |
singleton | 每个Spring IoC容器内同名称的bean只有一个实例(默认) |
prototype | 每次使用该bean时会创建新的实例 |
request | 每个HTTP请求生命周期内,创建新的实例(web环境中) |
session | 每个HTTP Session生命周期内,创建新的实例(web环境中) |
application | 每个ServletContext生命周期内,创建新的实例(web环境中) |
websocket | 每个WebSocket生命周期内,创建新的实例(Web环境中) |
如果想要更改 Bean 的作用域应该如何进行设置呢?
@Scope
我们可以通过修改@Scope注解中的value属性的值来修改Bean的作用域。
singleton
当我们直接在Spring中定义一个Bean时此时它默认的作用域是 singleton(单例)。
此时先定义一个类,然后将它交给Spring管理:
public class Dog { public String name; public Dog(){}; public Dog(String name){ this.name = name; } }
@Component public class Demo { @Bean public Dog dog() { Dog dog = new Dog(); return dog; } }
此时我们通过ApplicationContext对象来从容器中分两次拿取,看两次拿取的类是否相同。
@SpringBootApplication public class Application { public static void main(String[] args) { //获取Spring的上下文 ApplicationContext context = SpringApplication.run(Application.class, args); Object dog1 = context.getBean("dog"); Object dog2 = context.getBean("dog"); System.out.println(dog1); System.out.println(dog2); } }
从打印的结果中我们可以看出dog1和dog2这两个对象是相同的。
prototype
将Bean作用域修改为 prototype 之后再进行打印观察,通过结果可以看出是两个不同的对象:
@Component public class Demo { @Bean @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public Dog dog() { Dog dog = new Dog(); return dog; } }
注意:request,session,application,websocket这四中作用域下的Bean只能再Web环境中获取,否则会报如下异常:
@RestController @RequestMapping("/bean") public class BeanController { @Autowired private Dog dog1; @Autowired private Dog dog2; @RequestMapping("/fun") public String test() { return ""+dog1.toString()+"
"+dog2.toString()+"
"; } }
@RequestScope
被该注解修饰表示该Bean的作用域是 request 。
@Component public class Demo { @Bean @RequestScope public Dog dog() { Dog dog = new Dog(); return dog; } }
当通过浏览器获取结果是发现这两个Bean是相同的,但是如果再刷新一下浏览器就会发现两次访问获取的结果不同:
@SessionScope
被该注解修饰表示该Bean的作用域为 session 。
@Component public class Demo { @Bean @SessionScope public Dog dog() { Dog dog = new Dog(); return dog; } }
此时通过浏览器获取结果,可以从结果中得知同一个浏览器的结果相同,不同浏览器结果不同。
@ApplicationScope
该注解表示被修饰地Bean的作用域为 application 。
@Component public class Demo { @Bean @ApplicationScope public Dog dog() { Dog dog = new Dog(); return dog; } }
Application scope就是对于整个web容器来说,bean的作用域是ServletContext级别的。这个和
singleton有点类似,区别在于:Application scope是ServletContext的单例,singleton是一个
ApplicationContext的单例,在⼀个web容器中ApplicationContext可以有多个。
Bean的生命周期
Bean的生命周期指的是Bean对象从创建直到销毁的全过程。
Bean的生命周期大致可以分为以下5步:
实例化(为Bean对象分配内存空间);
属性赋值(Bean注入或装配,如@AutoWired);
初始化;
- 执行各种通知,如 BeanNameAware, BeanFactoryAware ,ApplicationContextAware 的接口方法
- 执行初始化方法:
- xml定义 init-method
- 使用注解的方式 @PostConstruct
- 执行初始化后置方法(BeanPostProcessor )
使用Bean;
销毁Bean。
光这么看有点抽象,下面用代码展示一下:
@Slf4j @Component public class Animal { public Dog dog; //实例化 public Animal() { log.info("执行构造方法"); } //属性注入 @Autowired public void setDog(Dog dog) { this.dog = dog; log.info("属性注入"); } //初始化 @PostConstruct public void init() { log.info("执行初始化方法"); } //使用 public void use() { log.info("use"); } //销毁 @PreDestroy public void destroy() { log.info("执行destroy方法"); } }
接下来执行这个类中的use()方法,然后观察打印结果:
@SpringBootApplication public class Application { public static void main(String[] args) { //获取Spring的上下文 ApplicationContext context = SpringApplication.run(Application.class, args); Animal animal = (Animal) context.getBean("animal"); animal.use(); } }
还没有评论,来说两句吧...