Spring(2) --Bean专题

你对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中的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 的生命周期?

参考/好文

(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

猜你喜欢

转载自www.cnblogs.com/liaowenhui/p/12750070.html