你对Spring中的bean了解吗?都有哪些作用域(Scope)?

Spring 官方文档对 bean 的解释是:

In Spring, the objects that form the backbone of your application and that are managed by the Spring IOC container are called beans. A bean is an object that is instantiated, assembled, and otherwise managed by a Spring IoC container.

翻译 ->

在 Spring 中,构成应用程序主干并由Spring IOC容器(ApplicationContext)管理的对象称为bean。bean是一个由Spring IOC容器实例化、组装(assembled)和管理的对象。

关键信息 ->

(1)bean是对象,一个或者多个,不限定个数;

(2)bean由Spring中一个叫IOC的容器管理;

(3)应用程序由bean构成;

Spring中的Bean有五种作用域(Scope):

(1) Singleton:一个Spring容器中只有一个Bean的实例,此为Spring的默认配置,全容器共享一个实例。

(2)Prototype:每次调用新建一个新的Bean实例。

(3)Request:Web项目中,给每一个http request新建一个Bean实例。

(4)Session:Web项目中,给每一个http session新建一个Bean实例。(5)GlobalSession:只在portal应用中有用,给每一个global http session新建一个Bean实例。

补充:Scope描述的是Spring容器如何创建Bean的实例的。

Spring中将一个类声明为Bean的注解和注入bean的注解有哪些?

声明为Bean的注解:

(1)@Component:通用的注解,可标注任意类为spring组件。如果一个Bean没有明确的角色,可以使用@Component注解标注。

(2)@Service:在业务逻辑层(service层)使用。

(3)@Repository:在数据访问层(dao层)使用。

(4)@Controller:在展现层(MVC->Spring MVC)使用,主要用于接收用户请求并调用Service层返回数据给前端页面。

注入Bean的注解(一般情况下通用):

(1)@Autowired:Spring提供的注解。

(2)@Inject:JSR-330提供的注解。

(3)@Resource:JSR-250提供的注解。

@Component和@Bean有什么区别呢?

(1)作用对象不同:@Component作用于类,@Bean作用于方法。

(2)@Component通常是通过类路径扫描来自动侦测以及自动装配到Spring容器中(使用@ComponentScan注解定义要扫描的路径从中找出识别了需要装配的类自动装配到spring的Bean容器中)。@Bean注解通常是在标有该注解的方法中定义产生这个bean,@Bean告诉Spring这是某个类的实例,当我需要用它的时候还给我。

(3)@Bean注解比@Component注解的自定义性更强,而且很多地方只能通过@Bean注解来注册Bean,比如第三方库中的类。

Spring是单例还是多例,怎么修改?

Spring的bean默认是单例的(sigleton)可以修改为多例(prototype),在此bean节点中添加一个属性,scope="prototype";

例如<bean id="xxx" class="全类名" scope="prototype"></bean>

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> <!--
scope属性控制当前bean的创建模式:
singleton:则当前bean处在单例模式中,默认就是此模式
prototype:则当前bean处在多例模式中
-->
<bean id="cart" class="com.spring.beans.Cart" scope="prototype"></bean>
</beans>

以下针对Spring对单例,多例进行说明

在Spring中,bean的Scope常被定义的两种模式:prototype(多例)和singleton(单例)。

singleton(单例):只有一个共享的实例存在,所有对这个bean的请求都会返回这个唯一的实例。

此外,singleton类型的bean定义从容器启动到第一次被请求而实例化开始,只要容器不销毁或退出,该类型的bean的单一实例就会一直存活,典型单例模式,如同servlet在web容器中的生命周期。

prototype(多例):对这个bean的每次请求都会创建一个新的bean实例,类似于new。

spring容器在输出prototype的bean对象时,会每次都重新生成一个新的对象给请求方,虽然这种类型的对象的实例化以及属性设置等工作都是由容器负责的,但是只要准备完毕,并且对象实例返回给请求方之后,容器就不在拥有当前对象的引用,请求方需要自己负责当前对象后继生命周期的管理工作,包括该对象的销毁。也就是说,容器每次返回请求方该对象的一个新的实例之后,就由这个对象“自生自灭”。

为什么用单例或者多例?何时用?

1)用单例,是因为没必要每个请求都新建一个对象,这样子既浪费CPU又浪费内存;

2)用多例,是为了防止并发问题;即一个请求改变了对象的状态,此时对象又处理另一个请求,而之前请求对对象状态的改变导致了对象对另一个请求做了错误的处理;

3)当对象含有可改变的状态时(更精确的说就是在实际应用中该状态会改变),则多例,否则单例。

Spring中的Bean是线程安全的吗?

Spring作为一个IOC/DI容器,帮助我们管理了许许多多的“bean”。但其实,Spring本身并没有提供线程安全的策略,对于每个bean的线程安全问题,根本原因是每个bean自身的设计,因此是否线程安全需要由开发者自己编写解决线程安全问题的代码。

无状态的对象,不管单例还是多例都是线程安全的。无状态的对象自然也就不会因为多个线程的交替调度而破坏自身状态导致线程安全问题。无状态对象包括我们经常使用的DO、DTO、VO这些只作为数据的实体模型的贫血对象,还有Service、DAO和Controller,这些对象并没有自己的状态,它们只是用来执行某些操作的。例如,每个DAO提供的函数都只是对数据库的CRUD,而且每个数据库Connection都作为函数的局部变量(局部变量是在用户栈中的,而且用户栈本身就是线程私有的内存区域,所以不存在线程安全问题),用完即关(或交还给连接池)。不要在bean中声明任何有状态的实例变量或类变量,如果必须如此,那么就使用ThreadLocal把变量变为线程私有的,如果bean的实例变量或类变量需要在多个线程之间共享,那么就只能使用Synchronized、Lock、CAS等这些实现线程同步的方法了。

补充说明:

什么是有状态和无状态对象?

1、有状态就是有数据存储功能。有状态对象(Stateful Bean),就是有实例变量的对象,可以保存数据,是非线程安全的。在不同方法调用间不保留任何状态。

2、无状态就是一次操作,不能保存数据。无状态对象(Stateless Bean),就是没有实例变量的对象.不能保存数据,是不变类,是线程安全的。

Bean的生命周期

  对于SpringBean来说,并不是启动阶段就会触发Bean的实例化,只有当客户端通过显式或者隐式的方式调用BeanFactory的getBean()方法时,它才会触发该类的实例化方法。当然对于BeanFactory来说,也不是所有的getBean()方法都会实例化Bean对象,例如作用域为singleton时,只会在第一次,实例化该Bean对象,之后会直接返回该对象。但如果使用的是 ApplicationContext 容器,则会在该容器启动的时候,立即调用注册到该容器所有 Bean 的实例化方法。

完整版流程如下:

简化翻译版:

1.instantiate[ɪns'tænʃɪeɪt] bean  实例化bean ,Bean容器找到配置文件中Spring Bean的定义,利用Java反射机制创建一个Bean的实例。

2.populate properties 封装属性(注入对象属性),如果涉及一些属性值,利用set()方法设置一些属性值。

3.执行Aware

(1)如果Bean实现BeanNameAware 接口,调用setBeanName()方法,传入Bean的名称

(2)如果 Bean 实现了BeanFactoryAware 接口,调用 setBeanFactory ()方法,将 BeanFactory 容器实例传入

(3)如果Bean实现了ApplicationContextAware接口,调用setApplicationContext()方法

4.如果存在类实现 BeanPostProcessor(前置处理),执行postProcessBeforeInitialization()。

5.InitializingBean、init-method检查和执行

(1)如果Bean实现InitializingBean 接口,执行 afterPropertiesSet()方法。

(2)调用自定义的初始化方法init-method.如果Bean在配置文件中的定义包含init-method属性,执行指定的方法。

6.如果存在类实现 BeanPostProcessor(后置处理) ,执行postProcessAfterInitialization().

7.Bean准备使用,执行业务处理。

8.执行销毁方法

(1)当要销毁Bean的时候,如果 Bean 实现了 DisposableBean 接口,执行 destroy() 方法。

(2)调用自定义的销毁方法destroy-method,当要销毁 Bean 的时候,如果 Bean 在配置文件中的定义包含 destroy-method 属性,执行指定的方法。

源码分析待补充

常见面试题?

(1) Spring Bean 的作用域有哪些?它的注册方式有几种?

(2) 什么是同名 Bean?它是如何产生的?应该如何避免?

(3) Bean 的生命周期?

(4) Spring是单例还是多例,怎么修改?

(5) 为什么用单例或者多例?何时用?

(6) Spring中的Bean是线程安全的吗?

(7) Spring中将一个类声明为Bean的注解和注入bean的注解有哪些?

(8) @Component和@Bean有什么区别呢?

参考/好文

(1) 书籍 -- SpringBoot实战 -- 汪云飞 编著

(2) 聊一聊Spring中的线程安全性 --

https://juejin.im/post/5a0045ef5188254de169968e

(3)《今天面试了吗》 - Spring

https://juejin.im/post/5e6d993cf265da575b1bd4af

(4) 拉钩课程 -- Java源码剖析

https://kaiwu.lagou.com/course/courseInfo.htm?courseId=59

Spring(2) --Bean相关的更多相关文章

  1. Spring Bean相关配置

    Bean相关配置 1.名称与标识 id 使用了约束中的唯一约束.里面不能出现特殊字符的 name 没有使用约束中的唯一约束.里面可以出现特殊字符. 设置对象的生命周期方法 init-method Be ...

  2. Spring bean相关

    Spring中指定Bean的作用于的方式 以下四种为例: 单例(默认,可以不用特殊表明) @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON) ...

  3. 在Spring的bean中注入HttpServletRequest解密

    我们可以在Spring的bean中轻松的注入HttpServletRequest,使用@Autowired HttpServletRequest request;就可以了. 但是,为什么我们可以直接这 ...

  4. 理解Spring的Bean工厂

    一提到工厂,我们先来回顾前面学习过的工厂方法和抽象工厂模式: 工厂方法:针对产品维度,能够产生新的产品,也能够产生新的产品工厂,既能够扩展产品维度.可是假设我们想在普通工厂上生产产品系列,就会特别麻烦 ...

  5. Spring的Bean,AOP以及工具类初探

    1.Bean(Ioc) BeanWrapper 根据JavaDoc中的说明,BeanWrapper提供了设置和获取属性值(单个的或者是批量的),获取属性描述信息.查询只读或者可写属性等功能.不仅如此, ...

  6. 【Spring】详解Spring中Bean的加载

    之前写过bean的解析,这篇来讲讲bean的加载,加载要比bean的解析复杂些,该文之前在小编原文中有发表过,要看原文的可以直接点击原文查看,从之前的例子开始,Spring中加载一个bean的方式: ...

  7. Java框架spring 学习笔记(九):Spring的bean管理(@Required、@Component、@Autowired、@Resource注解)

    注解:代码里面特殊的标记,使用注解可以完成相关功能 注解写法:@注解名称(属性名.属性值) @Required 用在set方法上,一旦用了这个注解,那么容器在初始化bean的时候必须要进行set,也就 ...

  8. Spring之Bean的生命周期详解

      通过前面多个接口的介绍了解了Bean对象生命周期相关的方法,本文就将这些接口的方法串起来,来了解Bean的完整的生命周期.而介绍Bean的生命周期也是面试过程中经常会碰到的一个问题,如果不注意就跳 ...

  9. Spring的bean管理(注解方式)

    注解:代码中的特殊标记,注解可以使用在类.方法.属性上面,使用注解可实现一些基本的功能.注解的写法是@注解名称(属性=属性值). 使用注解创建对象 第一步,创建Web项目,引入Spring的开发包 第 ...

随机推荐

  1. dataframe检查重复值,去重

    flag = df.price.duplicated() # flag = df.duplicated() #参考:https://www.cnblogs.com/trotl/p/11876292.h ...

  2. Fisco Bcos学习资料连接

    大牛博客:http://m.blog.csdn.net/sportshark FISCO BCOS学习资料索引;http://kb.bsnbase.com/webdoc/view/Pub4028813 ...

  3. nginx转发上传图片接口图片的时候,报错413

    我这边有一个接口是上传图片,使用nginx进行代理,上传大一点的图片,直接调用我的接口不会报错,但是调用nginx上传图片就会报错"413 Request Entity Too Large& ...

  4. Vue开发中的移动端适配(px转换成vw)

    1.项目根目录下,创建 .postcssrc.js 文件. 2.安装插件. -D (开发依赖) postcss-import postcss-url cssnano-preset-advanced - ...

  5. 如何使用交易开拓者(TB)开发数字货币策略

    更多精彩内容,欢迎关注公众号:数量技术宅.想要获取本期分享的完整策略代码,请加技术宅微信:sljsz01 为何使用交易开拓者(TB)作为回测工具 交易开拓者(后文以TB简称)是一个支持国内期货市场K线 ...

  6. 解决Linux所有命令不能使用的问题

    解决Linux所有命令不能使用的问题 出现这个问题说明你的 /etc/profile 配置出现了问题,一般是因为path配置出现了问题.排除添加内容中的错误,然后重启一个新窗口执行执行 source ...

  7. Java 方法内联

    什么是Java 方法内联? 我们先来看看普遍的内联函数含义.在维基百科中解释为: 内联函数:在计算机科学中,内联函数(有时称作在线函数或编译时期展开函数)是一种编程语言结构,用来建议编译器对一些特殊函 ...

  8. mini-web框架-装饰器-总结2(5.3.2)

    @ 目录 1.说明 2.代码 关于作者 1.说明 多级装饰器嵌套 带参数的装饰器 这里打印print(index) 会在函数定义的时候@test(222) 就被调用,返回一个test2继续装饰 2.代 ...

  9. VuePress教程之深入理解插件API

    VuePress教程之深入理解插件API 本文目录 1 VuePress教程之深入理解插件API 2 插件 ??? 2.1 暖暖身 2.2 插件如何运作 3 准备 3.1 Markdown 3.2 P ...

  10. 在库中使用schematics——ng add与ng update

    起步 创建一个angular库 ng new demo --create-application=false ng g library my-lib 可见如下目录结构 ├── node_modules ...