❤️❤️❤️Spring专栏更新中,各位大佬觉得写得不错,支持一下,感谢了!❤️❤️❤️ Spring + Spring MVC + MyBatis专栏
前面我们讲完了Spring中有关Bean的读和取,我们还没有好好去了解了解Bean对象,这篇 就是对Bean的深入学习。
限定程序中变量的可用范围叫做作用域,或者说在源代码中定义变量的某个区域就叫做作用域。而Bean 的作用域是指 Bean 在 Spring 整个框架中的某种行为模式,比如 singleton 单例作用域,就表示 Bean 在整个 Spring 中只有一份,它是全局共享的,那么当其他人修改了这个值之后,另一个人读取到的就是被修改的值。
Singleton 单例模式是一种创建型设计模式,它保证一个类只有一个实例,并提供该实例的全局访问点。 使用 Singleton 模式的主要目的是确保在一个应用程序中,某个类的对象只有一个,这样可以节省系统资源,避免 对同一数据的多重处理等问题。在实现时,我们需要注意线程安全、延迟初始化、序列化和反射等方面的问题。 一般来说,Singleton 模式适用于那些需要频繁访问的对象,例如日志记录器、数据库连接池、线程池等等。
有一个公共的 Bean,提供给 A 用户和 B 用户使用,然而在使用的途中 A 用户却“悄悄”地修 改了公共 Bean 的数据,导致 B 用户在使用时发生了预期之外的逻辑错误。
公共 Bean:
@Component
public class Users {
@Bean
public User user1() {
User user = new User();
user.setId(1);
user.setName("Java"); // 【重点:名称是 Java】
return user;
}
}
A 用户使用时,进行了修改操作:
@Controller
public class BeanScopesController {
@Autowired
private User user1;
public User getUser1() {
User user = user1;
System.out.println("Bean 原 Name:" + user.getName());
user.setName("悟空"); // 【重点:进⾏了修改操作】
return user;
}
}
B 用户再去使用公共 Bean 的时候:
@Controller
public class BeanScopesController2 {
@Autowired
private User user1;
public User getUser1() {
User user = user1;
return user;
}
}
打印 A 用户和 B 用户公共 Bean 的值:
public class App {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
BeanScopesController beanScopesController = context.getBean("beanScopesController",BeanScopesController.class);
System.out.println("A 对象修改之后 " + beanScopesController.getUser1().toString());
BeanScopesController2 beanScopesController2 = context.getBean("beanScopesController2",BeanScopesController2.class);
System.out.println("B 对象读取到的 " + beanScopesController2.getUser1().toString());
}
}
运行结果:
通过上面这个案例我们发现所有人的使用的都是同 一个对象,这也验证了我们之前说的:在 Spring 中 Bean 的作用域默认是 singleton 单例模式。
Spring 容器在初始化⼀个 Bean 的实例时,同时会指定该实例的作用域。Spring有 6 种作用域,最后四种是基于 Spring MVC 生效的:
其中前两种是 spring 核心作用域,而后 4 种是 spring mvc 中的作用域。
Spring 框架默认采用 Singleton 单例模式,主要是因为以下几点原因:
设置作用域有两种方法:
Ⅰ、直接设置值:@Scope("prototype") 🍓
还是前面的代码,我们给user1设置prototype作用域 (也可以设置成其他作用域)
运行:
通过@Scope(ConfigurableListableBeanFactory.SCOPE_PROTOTYPE)修改作用域
我们运行代码也可以可以得到与 前一方法 相同的结果:
所谓的生命周期指的是一个对象从诞生到销毁的整个生命过程,我们把这个过程就叫做一个对象的生命周期。 Bean 的生命周期分为以下 5 大部分:
销毁容器的各种方法,如 @PreDestroy、DisposableBean 接口方法、destroy-method。
执行流程如下图所示:
实例化和初始化是Bean生命周期中的两个不同阶段。
实例化:指根据配置文件或注解等方式,创建一个对象实例的过程。在Spring容器启动时,会根据定义的Bean定义信息创建相应的Bean实例,并将其添加到容器中进行管理。这个过程可以通过构造函数、工厂方法或者其他方式来实现。
初始化:指在Bean实例化后,进行必要的属性设置、调用接口方法以及执行自定义初始化方法等操作,使得Bean达到可以使用的状态。在Spring容器创建了Bean实例之后,会根据配置信息和需要执行一定的初始化操作,例如调用BeanPostProcessor接口中的回调方法、执行自定义的初始化方法等等。
总之,Bean的实例化和初始化是在Spring容器中管理Bean的重要环节,它们各自都有着不同的作用和实现方式。