成都 企业 网站建设计算机多媒体辅助教学网站开发
news/
2025/10/5 11:28:56/
文章来源:
成都 企业 网站建设,计算机多媒体辅助教学网站开发,品牌设计vi设计公司,wordpress模板淘宝客模板自适应文章目录 前言一、Bean 的作用域1.1 被修改的 Bean 案例1.2 作用域的定义1.3 Bean 的六种作用域1.4 Bean 作用域的设置 二、Spring 的执行流程 和 Bean 的生命周期2.1 Spring 的执行流程2.2 Bean 的生命周期2.3 Bean 生命周期的演示 前言
Bean 是 Spring 框架中的一个核心概念… 文章目录 前言一、Bean 的作用域1.1 被修改的 Bean 案例1.2 作用域的定义1.3 Bean 的六种作用域1.4 Bean 作用域的设置 二、Spring 的执行流程 和 Bean 的生命周期2.1 Spring 的执行流程2.2 Bean 的生命周期2.3 Bean 生命周期的演示 前言
Bean 是 Spring 框架中的一个核心概念它是指由 Spring 容器管理的对象实例。在使用 Spring 进行开发时我们通常会定义各种各样的 Bean用于承载应用程序的不同功能和组件。然而很多开发者可能只关注了 Bean 的定义和使用方式而忽略了 Bean 的作用域和生命周期这两者对于一个应用程序的性能、稳定性和可维护性都至关重要。
在本文中我将深入讨论 Bean 的作用域和生命周期并解释它们对于 Spring 应用程序的影响。我会尽量用简单明了的语言来阐述这些概念以便读者能够轻松理解和应用到自己的开发实践中。
一、Bean 的作用域
初次看到 Bean 的作用域这个名词可能会令我们一头雾水但是没关系接下来的一个简单案例将会告诉我们什么是 Bean 的作用域。
1.1 被修改的 Bean 案例
现在有一个公共的 Bean对象可以供 A 和 B 两个用户使用但是 A 在使用这个 Bean 对象的时候却悄悄的对这个 Bean 的数据进行了修改那么会不会导致 B 用户在使用这个 Bean 对象的时候发生预期之外的结果呢
创建一个 UserBean 的类它的作用是通过 Bean 注解的方式将 User 对象存储到 Spring 容器中其中 User 包含一个 id 和 name 属性
Component
public class UserBeans {Beanpublic User getUser(){User user new User();user.setId(123);user.setName(张三);return user;}
}
然后创建一个 UserController1 类通过 Controller 注解将其存储到 Spring 容器中然后使用属性注解获取 Spring 容器中的 Bean 对象。另外创建一个 printUser 方法里面创建一个临时引用 myUser 指向 Bean 对象然后对这个 Bean 的数据进行修改
Controller
public class UserController1 {Autowiredprivate User user;public void printUser(){System.out.println(user: user);User myUser user;myUser.setName(李四);System.out.println(myUser: myUser);System.out.println(user: user);}
}另外再创建一个 UserController2同样使用 Controller 注解将其存储到 Spring 容器中然后使用属性注解获取 Spring 容器中的 Bean 对象。另外创建一个 printUser 方法只打印获取到的 Bean 对象
Controller
public class UserController2 {Resourceprivate User user;public void printUser(){System.out.println(UserController2: user - user);}
}在启动类中的 main 方法分别通过 ApplicationContext 获取 UserController1 和 UserController2然后分别执行其中的方法观察修改 Bean 对象后产生的影响。
public static void main(String[] args) {ApplicationContext context new ClassPathXmlApplicationContext(spring-config.xml);UserController1 userController1 context.getBean(userController1, UserController1.class);UserController2 userController2 context.getBean(userController2, UserController2.class);userController1.printUser();System.out.println();userController2.printUser();
}执行的结果如下 从运行的结果来看当 UserController1 修改了 Bean 在数据此时通过 UserController2 获取的 Bean 的数据也被修改了那么就说明一个 Bean 在 Spring 中的储存只有一份并且是单例模式的。因此 Spring 容器中的 Bean 的默认作用域就是单例模式singleton的。
1.2 作用域的定义
作用域Scope是在编程中用于描述变量或标识符在程序中可访问的范围。换句话说它规定了变量在哪些部分可以被引用和使用。作用域是一个重要的概念因为它可以帮助程序员避免命名冲突和理解变量在代码中的生命周期。
在 Spring 框架中作用域Scope就是用来定义 Bean 对象的生命周期和可见性规则。作用域决定了在不同的上下文环境中Spring 容器如何管理和提供 Bean 对象。例如在定义一个 Bean 的时候我们可以指定其作用域从而决定它在应用程序中的行为表现。
1.3 Bean 的六种作用域
Spring 容器在初始化一个 Bean 的实例的时候同时会指定该实例的作用域如果我们不修改要指定的作用域Spring 就会默认指定一个默认的作用域。以下是 Spring 中的六种作用域其中最后四种是基于 Spring MVC 生效的因此本文先不讨论。 单例作用域singleton这是 Spring 容器默认的作用域。在整个应用程序的生命周期中只会创建一个该类型的 Bean 实例并且所有对该 Bean 的引用都会执行同一个对象。这种作用域适用于哪些无状态、线程安全的 Bean 对象例如工具类、配置类等。 原型作用域prototype每次请求 Bean 对象的时候Spring 容器都会创建一个新的 Bean 实例因此在不同的请求中得到的是不同的对象实例。原型作用域适用于那先状态较多需要频繁创建和销毁的对象比如某些与会话相关的 Bean。 请求作用域request请求作用域是在 Web 应用中常用的作用域。它表示每次 HTTP 请求都会创建一个新的 Bean 实例该实例仅在当前请求的处理过程中有效。当请求结束后该 Bean 会被销毁。这样的作用域通常用于存储和处理与单个请求相关的数据。 会话作用域session会话作用域是在 Web 应用中基于用户会话的作用域。每个 HTTP 会话Session对应一个 Bean 实例该实例在整个会话的生命周期内有效。这种作用域适用于需要在整个会话期间保持状态的对象比如用户登录信息等。 全局作用域application全局作用域是指在整个 Web 应用程序的生命周期内只创建一个 Bean 实例。该作用域的 Bean 在整个应用中可见适用于那些在整个应用中需要共享的状态信息。 HTTP WebSocket 作用域websocket HTTP WebSocket 作用域是基于 WebSocket 连接的作用域。每个 WebSocket 连接对应一个 Bean 实例该实例在 WebSocket 连接的整个生命周期内有效。 单例作用域singleton和全局作用域application之间的区别 单例作用域和全局作用域都只创建一个 Bean 对象那么它们之间有什么区别呢
1. 定义位置
单例作用域是 Spring Core 的一部分在整个 Spring IoC 容器中生效。它适用于任何类型的 Spring 应用不仅限于 Web 应用。全局作用域是 Spring Web 的一部分在 Servlet 容器中生效。它是专门为 Web 应用设计的通过 Spring Web 库提供支持。
2. 作用范围
单例作用域只保证在 Spring IoC 容器中每个 Bean 只会有一个实例。在整个应用程序中不同的 Spring IoC 容器可能会有不同的实例。全局作用域确保在整个 Web 应用程序中每个 Bean 只会有一个实例。无论是在同一个 Servlet 容器中还是不同的 Servlet 容器中都只有一个实例。
3. 应用场景
单例作用域适用于那些无状态、线程安全的 Bean例如工具类、配置类等。由于单例 Bean 在整个应用中只有一个实例因此在性能和资源利用方面有一定的优势。全局作用域适用于那些在整个 Web 应用中需要共享状态信息的 Bean比如全局的配置对象、全局缓存等。通过全局作用域我们可以确保这些对象在整个应用中只有一个实例而不受多个 Servlet 容器的影响。
4. 管理容器
单例作用域的管理是 Spring IoC 容器负责的它由 Spring Core 提供的 IoC 容器管理与 Web 应用无关。全局作用域的管理需要由 Spring Web 库提供的 Servlet 容器来管理它与 Web 应用的生命周期相关。
总结来说单例作用域适用于整个 Spring IoC 容器保证每个 Bean 在容器中只有一个实例而全局作用域适用于整个 Web 应用保证每个 Bean 在整个应用中只有一个实例。选择合适的作用域取决于具体的应用需求和设计考虑。
1.4 Bean 作用域的设置
在 Spring 中设置 Bean 作用域可以通过两种方法XML 配置和注解配置。
1. XML 配置 在 XML 配置文件中的 bean标签中可以使用 scope 属性来设置 Bean 的作用域。例如对于原型作用域的 Bean可以这样配置
bean idmyBean classcom.spring.demo.MyBean scopeprototype!-- Bean 的属性配置 --
/bean其中scope指定的是作用域的名称如prototype、singleton。
2. 注解配置
使用注解配置 Bean 的作用域更加的简洁。在 Spring 中可以使用 Scope 注解来指定 Bean 的作用域例如对刚才的 UserBeans 类指定原型作用域
Component
public class UserBeans {Bean(name {user1})// Scope(prototype) // 原型模式Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) // 使用全局变量设置public User getUser(){User user new User();user.setId(123);user.setName(张三);return user;}
}此时Scope中的参数可以说作用域的名称如prototype也可以通过ConfigurableBeanFactory类来指定。ConfigurableBeanFactory类的源码 可以发现ConfigurableBeanFactory类也是对作用域名的封装。
当作用域设置为原型模型的时候再次运行刚才修改 Bean 内容的代码 此时就能够发现两个 UserController 获取到的都是一个全新的 Bean 对象即使一个修改也不会对另一个造成影响。
二、Spring 的执行流程 和 Bean 的生命周期
2.1 Spring 的执行流程
Spring 执行流程 启动 Spring 容器 Spring 容器在启动时会读取配置文件或者扫描注解来获取 Bean 的定义信息。 实例化 Bean分配内存空间从无到有 Spring 容器根据配置信息或者注解的定义实例化 Bean 对象。实例化过程可能会涉及构造函数的调用和依赖对象的创建。 Bean 注册到 Spring 容器存操作 实例化后的 Bean 被注册到 Spring 容器中容器将其纳入管理范围并为每个 Bean 分配一个唯一的标识符通常是 Bean 的名称或者 ID。 Bean 初始化初始化操作 如果 Bean 的定义中配置了初始化方法例如使用 init-method 属性或者 PostConstruct 注解Spring 容器会在实例化之后调用该初始化方法用于执行一些初始化逻辑。 将 Bean 装配到需要的类中取操作 当其他类需要使用某个 Bean 时Spring 容器会根据依赖注入的配置将对应的 Bean 自动注入到需要的类中。这样其他类就可以直接使用该 Bean 的实例而不需要关心 Bean 对象的创建和管理过程。 使用 Bean 现在Bean 已经被装配到需要的类中可以在其他类中直接使用它了。 Bean 销毁销毁操作 如果 Bean 的定义中配置了销毁方法例如使用 destroy-method 属性或者 PreDestroy 注解Spring 容器会在容器关闭时调用该销毁方法用于执行一些清理操作。
需要注意的是Bean 的生命周期在 Spring 容器的控制下开发者无需手动管理 Bean 的创建和销毁过程这就是 Spring IoC控制反转的核心思想。通过依赖注入我们能够更专注于业务逻辑的实现而不需要关心对象的创建和管理。
2.2 Bean 的生命周期
Bean 的生命周期是指一个 Bean 实例从被创建到被销毁的整个过程。在 Spring 容器中Bean 的生命周期主要包含以下阶段 实例化这个阶段 Spring 容器会根据配置信息和注解创建 Bean 实例。这是 “从无到有” 的过程即分配内存空间并调用构造方法来创建 Bean 实例。 设置属性Bean 的注入和装配在实例化后Spring 容器会根据配置文件或注解将属性值注入到 Bean 实例中。这是依赖注入Dependency Injection的过程通过属性或构造方法来设置 Bean 的属性值。 Bean 初始化在属性赋值完成后Spring 容器会执行以下步骤来初始化 Bean 各种通知如果 Bean 实现了相应的 Aware 接口Spring 会通过回调方式通知 Bean 相应的状态例如 BeanNameAware、BeanFactoryAware、ApplicationContextAware 等。初始化前置方法执行 BeanPostProcessor 初始化前置方法如 postProcessBeforeInitialization。初始化方法XML方式和注解方式如果 Bean 定义了初始化方法PostConstruct 注解或实现了 InitializingBean 接口Spring 容器会在设置属性后调用该方法进行进一步的初始化。初始化后置方法如果 Bean 定义了初始化后置方法如 BeanPostProcessor 接口实现类的 postProcessAfterInitialization 方法Spring 容器会在 Bean 初始化完成后调用该方法。 使用 Bean在初始化完成后Bean 实例就可以被应用程序使用了。它会被注入到其他类中或者通过 Spring 容器获取并调用它的方法。 销毁 Bean 对象在容器关闭或者程序结束时Spring 容器会执行以下步骤来销毁 Bean 销毁前置方法如果 Bean 定义了销毁前置方法destroy-methodSpring 容器会在 Bean 销毁前调用该方法。销毁方法XML方式和注解方式如果 Bean 定义了销毁方法PreDestroy 注解或实现了 DisposableBean 接口Spring 容器会在 Bean 销毁时调用该方法进行清理操作。
2.3 Bean 生命周期的演示
下面的代码演示了一个完整的 Bean 生命周期过程并展示了 Spring 中 Bean 的各个阶段的回调方法。让我们来看一下 Bean 生命周期的执行流程 Component
public class BeanComponent implements BeanNameAware, BeanPostProcessor {Overridepublic void setBeanName(String s) {System.out.println(执行了通知Bean name - s);}// xml 的初始化方法public void myInit(){System.out.println(XML 方式初始化);}PostConstructpublic void doPostConstruct(){System.out.println(注解 的初始化方法);}public void sayHi(){System.out.println(do sayHi());}PreDestroypublic void preDestroy(){System.out.println(do PreDestroy);}// 前置方法Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println(do postProcessBeforeInitialization);return bean;}// 后置方法Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println(do postProcessAfterInitialization);return bean;}
}
首先需要在 spring-config.xml配置文件中增加以下内容
!-- XML 配置方式 --bean idbeanComponentclasscom.spring.demo.component.BeanComponent scopeprototype init-methodmyInit /bean模拟 Bean 的生命周期 实例化 Bean Spring 容器读取配置文件或扫描注解发现了 BeanComponent 的定义并实例化了该 Bean。此时还没有调用 Bean 的构造方法。 设置属性Bean 的注入和装配 如果有需要Spring 容器会将相应的属性注入到 BeanComponent 实例中。 Bean 初始化 执行各种通知因为 BeanComponent 实现了 BeanNameAware 接口所以 setBeanName 方法会被调用打印输出 执行了通知Bean name - beanComponent。初始化前置方法如果是 XML 配置方式myInit 方法会被调用打印输出 XML 方式初始化。初始化方法PostConstruct 注解doPostConstruct 方法会被调用打印输出 注解 的初始化方法。初始化后置方法postProcessAfterInitialization 方法会被调用打印输出 do postProcessAfterInitialization。 使用 Bean 在初始化完成后BeanComponent 实例可以被应用程序使用例如调用 sayHi() 方法打印输出 do sayHi()。 销毁 Bean 对象 在容器关闭或程序结束时preDestroy 方法会被调用打印输出 do PreDestroy。
需要注意的是在上述示例中使用了 BeanPostProcessor 接口来实现前置和后置方法。这个接口提供了在 Bean 初始化前后对 Bean 进行额外处理的能力。在实际应用中可以通过实现 BeanPostProcessor 接口来自定义一些特定的处理逻辑例如 AOP 的代理生成。
启动类的main方法 public static void main(String[] args) {ClassPathXmlApplicationContext context new ClassPathXmlApplicationContext(spring-config.xml);BeanComponent beanComponent context.getBean(beanComponent, BeanComponent.class);beanComponent.sayHi();}执行结果 这里发现执行了两次通知第一次通常是因为在创建 Spring 上下文的时候会执行 Bean 的实例化第二次执行通常是因为采用的是原型模式当执行getBean的会创建一个新的 Bean 对象。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/928189.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!