变量的作用域
变量的作用域是指一个变量生效的范围,作用的范围。比如定义了一个类变量,就意味着类里面的所有方法都可以使用;如果变量定义在方法里面,就称为方法变量,方法变量只能在方法里面去使用。
Bean的作用域
Bean是Spring里面存储的对象,Bean的作用域指的是Bean对象在Spring容器里面的行为。
下面我们用一个例子来看Bean作用域问题:
- 我们先创建一个公共类Users,调用getUser()方法可以或得一个公共的User对象,我们设置这个公共类的User的id为222,User的name为李四:
package com.java.demo.model;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
// 公共类
@Component
public class Users {
@Bean("user")
public User getUser(){
User user=new User();
user.setId(222);
getUser().setName("李四");
return user;
}
}
- 假设有两个人需要对这个公共类进行改进,在这里我们用UserController2和UserController3来代表这两个人。
- UserController2对公共对象的操作如下:
import com.java.demo.model.User;
import com.java.demo.model.Users;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController2 {
@Autowired
private User user;
public void doMethod(){
User user2=user;
System.out.println("UserController2修改之前"+user);
user2.setName("张三");
user2.setId(1111);
System.out.println("UserController2修改之前:"+user);
}
}
UserController2先定义了一个User类型的变量user2然后将user给user2,然后打印了一下修改之前的user,接着对user2进行id设置和name设置,最后打印一下修改后的user。
可以看到,公共对象user已经被修改了,id和name都被UserController2进行了修改。虽然UserController2是对user2进行了操作,可是还是改变了原本的user。
我们再看一下 UserController3:
package com.java.demo.controller;
import com.java.demo.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;
@Controller
public class UserController3 {
@Autowired
private User user;
public void doMethod(){
System.out.println("UserController3 的user:"+user);
}
}
UserController3并没有对公共对象user进行任和操作,只是在doMethod方法里面打印了一下公共对象user。UserController3希望拿到的user是没有被改动的user,那我们来看一下代码执行的结果(我们在main方法里面,先调用UserController2的doMethod方法,再调用UserController3的doMethod方法):
代码执行结果:
结果发现,虽然UserController2重新定义了一个变量,然后进行修改,但是原来的公共对象依旧被改动了,导致UserController3拿到的公共对象user已经是被改动后的了。
导致这样结果的原因就是:
private User user;
User user2=user;
这里代码实际上定义一个User类型的变量,这个变量指向的是user对象,并没有新的对象。这时候使用user2去修改对象的时候,就相当于修改了user对象。
归根结底导致这个问题的原因就是Bean的作用域,Bean对象默认的是单例模式。(单例模式是指在程序的运行期间只有一份)。
- 如何避免默认单例模式带来的问题?
手动设置,通过@Scope注解,如@Scope(“prototype”)、prototype就是原型模式:
package com.java.demo.model;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
// 公共类
@Component
public class Users {
@Bean
@Scope("prototype")
public User getUser(){
User user=new User();
user.setId(222);
user.setName("李四");
return user;
}
}
Bean作用域类型:
概念:Bean作用域指的是Bean在Spring容器中的某种行为,比如单例模式,比如原型模式等。
- singleton:单例作用域(默认的作用域)
补充问题:单例模式的Bean是线程安全的吗?不是,因为所有人都可以操作这个公共变量,所以不是线程安全的,使用ThreadLocal可以变成线程安全的。 - prototype:原型作用域(多例模式)
- request:请求作用域,只适用于Spring MVC项目(就是Spring Web项目)
- session:回话作用域,一个Http会话共享一个Bean,是适用于Spring MVC项目。
- application:全局作用域,表示的是一个Context容器共享一个作用域。只适用于Spring MVC项目。
- websocket:Http WebSocket作用域,只适用于Webscoket作用域。
Spring的生命周期
- 启动容器
- 读取配置文件,进行Bean的实例化
- 将Bean加入到容器中
- 装配Bean属性(给当前类的属性赋值)
Bean的生命周期
- 实例化(内存空间的分配)
- 设置Bean属性(进行依赖注入,将依赖的Bean赋值到当前类的属性上)
- Bean的初始化
3.1 执行各种通知
3.2 初始化的前置方法
3.3 初始化方法
3.4 初始化的后置方法 - 使用Bean
- 销毁Bean